home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1997 May: Tool Chest / Dev.CD May 97 TC.toast / Sample Code / Development Tools & Languages / AppsToGo / DTS.Lib / Utilities.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-09-22  |  88.0 KB  |  3,281 lines  |  [TEXT/MPS ]

  1. /*
  2. **    Apple Macintosh Developer Technical Support
  3. **
  4. **    Collection of Utilities for DTS Sample code
  5. **
  6. **    File:        Utilities.c
  7. **
  8. **    Copyright © 1988-1993 Apple Computer, Inc.
  9. **    All rights reserved.
  10. */
  11.  
  12. /* You may incorporate this sample code into your applications without
  13. ** restriction, though the sample code has been provided "AS IS" and the
  14. ** responsibility for its operation is 100% yours.  However, what you are
  15. ** not permitted to do is to redistribute the source as "DSC Sample Code"
  16. ** after having made changes. If you're going to re-distribute the source,
  17. ** we require that you make it clear in the source that the code was
  18. ** descended from Apple Sample Code, but that you've made changes. */
  19.  
  20. #ifndef OBSOLETE
  21. #define OBSOLETE
  22. #endif
  23.  
  24. #ifndef __CONTROLS__
  25. #include <Controls.h>
  26. #endif
  27.  
  28. #ifndef __DESK__
  29. #include <Desk.h>
  30. #endif
  31.  
  32. #ifndef __DEVICES__
  33. #include <Devices.h>
  34. #endif
  35.  
  36. #ifndef __ERRORS__
  37. #include <Errors.h>
  38. #endif
  39.  
  40. #ifndef __EVENTS__
  41. #include <Events.h>
  42. #endif
  43.  
  44. #ifndef __FONTS__
  45. #include <Fonts.h>
  46. #endif
  47.  
  48. #ifndef __GWLAYERS__
  49. #include "GWLayers.h"
  50. #endif
  51.  
  52. #ifndef __LOWMEM__
  53. #include <LowMem.h>
  54. #endif
  55.  
  56. #ifndef __MENUS__
  57. #include <Menus.h>
  58. #endif
  59.  
  60. #ifndef __NOTIFICATION__
  61. #include <Notification.h>
  62. #endif
  63.  
  64. #ifndef __OSEVENTS__
  65. #include <OSEvents.h>
  66. #endif
  67.  
  68. #ifndef __PACKAGES__
  69. #include <Packages.h>
  70. #endif
  71.  
  72. #ifndef __RESOURCES__
  73. #include <Resources.h>
  74. #endif
  75.  
  76. #ifndef __SCRIPT__
  77. #include <Script.h>
  78. #endif
  79.  
  80. #ifndef __STRINGS__
  81. #include <Strings.h>
  82. #endif
  83.  
  84. #ifndef __TEXTEDIT__
  85. #include <TextEdit.h>
  86. #endif
  87.  
  88. #ifndef __TOOLUTILS__
  89. #include <ToolUtils.h>
  90. #endif
  91.  
  92. #ifndef __APPLEEVENTS__
  93. #include <AppleEvents.h>
  94. #endif
  95.  
  96. #ifndef __COMPONENTS__
  97. #include <Components.h>
  98. #endif
  99.  
  100. #ifndef __FIXMATH__
  101. #include <FixMath.h>
  102. #endif
  103.  
  104. #ifndef __GESTALTEQU__
  105. #include <GestaltEqu.h>
  106. #endif
  107.  
  108. #ifndef __FOLDERS__
  109. #include <Folders.h>
  110. #endif
  111.  
  112. #ifndef __MOVIES__
  113. #include <Movies.h>
  114. #endif
  115.  
  116. #ifndef __PALETTES__
  117. #include <Palettes.h>
  118. #endif
  119.  
  120. #ifndef __STRINGUTILS__
  121. #include "StringUtils.h"
  122. #endif
  123.  
  124. #ifndef __TRAPS__
  125. #include <Traps.h>
  126. #endif
  127.  
  128. #include "Utilities.h"
  129.  
  130.  
  131.  
  132. /*****************************************************************************/
  133.  
  134.  
  135.  
  136. /* Global variables -- See Utilities.h for more explanation. */
  137.  
  138. short            gMachineType;            /* which machine this is */
  139. short            gSystemVersion;            /* System version number */
  140. short            gProcessorType;            /* which CPU this is */
  141. Boolean            gHasFPU;                /* true if machine has an FPU */
  142. short            gQDVersion;                /* major QD version #; 0 for original,
  143.                                                     1 for color QD, 2 for 32-bit QD */
  144. short            gKeyboardType;            /* which type of keyboard is present */
  145. short            gAppleTalkVersion;        /* AppleTalk version number */
  146. Boolean            gHasPMMU;                /* true if machine has a PMMU or equivalent */
  147. short            gAUXVersion;            /* major A/UX version number (0 if not present) */
  148.  
  149. Boolean            gHasWaitNextEvent;
  150. short            gAppResRef;
  151. Boolean            gInBackground;
  152. Str255            gAppName;
  153. OSType            gSignature = '\?\?\?\?';
  154. Boolean            gHaveSystemInfo;
  155.  
  156. GrafPtr            gScreenPort;
  157.  
  158. long            gQTVersion;                    /* QuickTime version (0 means not available). */
  159. Component        gMovieControllerComponent;    /* QuickTime movie controller component reference. */
  160.                                             /* Call InitQuickTime to initialize these globals. */
  161.  
  162. OSErr            gGetWindowErr;
  163. WindowTemplate    gWindowTemplate;
  164. WindowTemplate    gOpenedWindowTemplate;
  165. ControlHandle    gWhichCtlHit;
  166. long            gWhichCtlWhen;
  167. Boolean            gWhichCtlDbl;
  168. Boolean            gWhichCtlTracking;
  169.  
  170. ModalFilterUPP    gAlertFilterUPP;
  171. ModalFilterUPP    gKeyEquivFilterUPP;
  172.  
  173. static Handle    gScrollProc;
  174. Handle            gPopupProc;
  175. static Handle    gButtonProcs[radioButProc + useWFont + 1];
  176. static Rect        gWindowPlacementRect;
  177.  
  178. static DrawControlProcPtr    gDrawControl;
  179. GetButtonVariantProcPtr        gGetButtonVariant;
  180.  
  181. /* For PowerPC, we must supply an instantiation of the qd globals - MPW does it for you */
  182. #ifdef powerc
  183. #ifndef __MWERKS__
  184. QDGlobals    qd;
  185. #endif
  186. #endif
  187.  
  188.  
  189.  
  190. /* The following creates global routine descriptors in our global address space.
  191. ** It saves us having to check at runtime whether or not they are initialized and
  192. ** then having to allocate them on the heap using NewRoutineDescriptor.
  193. ** But it has the disadvantage of requiring some conditional compilation. */
  194.  
  195. #if USESROUTINEDESCRIPTORS
  196. static RoutineDescriptor gAlertFilterRD        = BUILD_ROUTINE_DESCRIPTOR (uppModalFilterProcInfo, AlertFilter);
  197. static RoutineDescriptor gKeyEquivFilterRD    = BUILD_ROUTINE_DESCRIPTOR (uppModalFilterProcInfo, KeyEquivFilter);
  198. ModalFilterUPP    gAlertFilterUPP                = &gAlertFilterRD;
  199. ModalFilterUPP    gKeyEquivFilterUPP            = &gKeyEquivFilterRD;
  200. #else
  201. ModalFilterUPP    gAlertFilterUPP                = AlertFilter;
  202. ModalFilterUPP    gKeyEquivFilterUPP            = KeyEquivFilter;
  203. #endif
  204.  
  205.  
  206.  
  207. /*****************************************************************************/
  208. /*****************************************************************************/
  209.  
  210. #ifdef applec
  211. #pragma segment UtilMain
  212. #endif
  213.  
  214. /*****************************************************************************/
  215. /*****************************************************************************/
  216.  
  217.  
  218.  
  219. Rect    SetWindowPlacementRect(Rect *rct)
  220. {
  221.     Rect    r;
  222.  
  223.     r = gWindowPlacementRect;
  224.     if (rct) gWindowPlacementRect = *rct;
  225.     return(r);
  226. }
  227.  
  228.  
  229.  
  230. /*****************************************************************************/
  231.  
  232.  
  233.  
  234. /* Given an alert ID and a window pointer the alert relates to, this function
  235. ** will center the alert’s rectangle before showing it on the proper screen.
  236. ** This follows the Apple Human Interface Guidelines for where to place a
  237. ** centered window on the screen.  If the alert is not closely associated with
  238. ** another window, pass a nil for the window pointer of the related window.  If
  239. ** you pass a nil, the alert is simply displayed where the resource
  240. ** would indicate.  Note that if an error occurs when getting the resource for
  241. ** the alert, then the alert is not displayed, and the returned value is not
  242. ** the item hit, but is the error that occured when reading the resource. */
  243.  
  244. short    CenteredAlert(short alertID, WindowPtr relatedWindow, ModalFilterUPP filter)
  245. {
  246.     AlertTHndl    alertHandle;
  247.     WindowPtr    tempWindow;
  248.     Rect        alertRect, sizeInfo;
  249.     short        itemHit;
  250.     char        hstate;
  251.     OSErr        err;
  252.  
  253.     itemHit = 1;
  254.  
  255.     if (!SimpleCanDialog()) {
  256.         alertHandle = (AlertTHndl)GetAppResource('ALRT', alertID, &err);
  257.         if (err) return((short)err);
  258.  
  259.         hstate = LockHandleHigh((Handle)alertHandle);
  260.             /* Do our part to help prevent fragmentation. */
  261.  
  262.         alertRect = (*alertHandle)->boundsRect;
  263.             /* Preserve the real alert bounding rectangle. */
  264.  
  265.         tempWindow = NewWindow(nil, &alertRect, "\p", false, dBoxProc, (WindowPtr)nil, false, 0);
  266.         if (tempWindow) {
  267.             /* Use an invisible temporary window to calculate where the alert will go. */
  268.  
  269.             SetRect(&sizeInfo, 0, 0, 0, 0);
  270.             (*alertHandle)->boundsRect = CenterWindow(tempWindow, relatedWindow, sizeInfo);
  271.             DisposeWindow(tempWindow);
  272.         }
  273.  
  274.         itemHit = Alert(alertID, filter);
  275.  
  276.         alertHandle = (AlertTHndl)GetAppResource('ALRT', alertID, &err);
  277.         if (alertHandle) {
  278.             (*alertHandle)->boundsRect = alertRect;
  279.             HSetState((Handle)alertHandle, hstate);
  280.         }        /* Restore the resource's bounding rect, so if this resource is ever used
  281.                 ** not through this function, it will open where the resource indicates. */
  282.  
  283.     }
  284.  
  285.     return(itemHit);
  286. }
  287.  
  288.  
  289.  
  290. /*****************************************************************************/
  291.  
  292.  
  293.  
  294. /* Given two rects, this function centers the second one within the first. */
  295.  
  296. void    CenterRectInRect(Rect outerRect, Rect *innerRect)
  297. {
  298.     PositionRectInRect(outerRect, innerRect, FixRatio(1, 2), FixRatio(1, 2));
  299. }
  300.  
  301.  
  302.  
  303. /*****************************************************************************/
  304.  
  305.  
  306.  
  307. /* Center a window within a particular device.  The device to center the window
  308. ** within is determined by passing a related window.  This allows related
  309. ** windows to be kept on the same device.  This is useful if an alert is related
  310. ** to a specific window, for example. */
  311.  
  312. Rect    CenterWindow(WindowPtr window, WindowPtr relatedWindow, Rect sizeInfo)
  313. {
  314.     WindowPtr    whichDevice;
  315.     Rect        deviceRect, oldWindowRect, newWindowRect, contentRect;
  316.     short        h, v, hh, vv;
  317.  
  318.     if (!(whichDevice = relatedWindow))
  319.         whichDevice = window;
  320.             /* If we have a window to center against, use the device for that window,
  321.             ** else use the device for the window that is getting centered. */
  322.  
  323.     deviceRect = GetWindowDeviceRectNMB(whichDevice);
  324.         /* We now have the rectangle of the device we want to center within. */
  325.  
  326.     if (!EmptyRect(&gWindowPlacementRect))
  327.         deviceRect = gWindowPlacementRect;
  328.  
  329.     contentRect = GetWindowContentRect(window);        /* Get where the window is now. */
  330.     h = hh = contentRect.right  - contentRect.left;
  331.     v = vv = contentRect.bottom - contentRect.top;
  332.     if (sizeInfo.left)
  333.         if (h < sizeInfo.left)
  334.             h = sizeInfo.left;
  335.     if (sizeInfo.right)
  336.         if (h > sizeInfo.right)
  337.             h = sizeInfo.right;
  338.     if (sizeInfo.top)
  339.         if (v < sizeInfo.top)
  340.             v = sizeInfo.top;
  341.     if (sizeInfo.bottom)
  342.         if (v > sizeInfo.bottom)
  343.             v = sizeInfo.bottom;
  344.     contentRect.right  = contentRect.left + h;
  345.     contentRect.bottom = contentRect.top  + v;
  346.  
  347.     oldWindowRect = GetWindowStructureRect(window);
  348.     oldWindowRect.right  += (h - hh);
  349.     oldWindowRect.bottom += (v - vv);
  350.     newWindowRect = oldWindowRect;
  351.  
  352.     PositionRectInRect(deviceRect, &newWindowRect, FixRatio(1, 2), FixRatio(1, 3));
  353.         /* Figure out the new window strucRect so we can compare it against
  354.         ** the old strucRect.  This will tell us how much to move the window. */
  355.  
  356.     OffsetRect(&contentRect, newWindowRect.left - oldWindowRect.left,
  357.                             newWindowRect.top  - oldWindowRect.top);
  358.         /* Calculate the new content rect. */
  359.  
  360.     MoveWindow(window, contentRect.left, contentRect.top, false);
  361.         /* Move the window to the new location. */
  362.  
  363.     return(contentRect);
  364. }
  365.  
  366.  
  367.  
  368. /*****************************************************************************/
  369.  
  370.  
  371.  
  372. /* Close a window.  This handles desk accessory and application windows.  Use
  373. ** this call (instead of DisposeAnyWindow) if the memory for the window was
  374. ** allocated by you.  (Same as CloseWindow v.s. DisposeWindow.) */
  375.  
  376. void    CloseAnyWindow(WindowPtr window)
  377. {
  378.     if (IsDAWindow(window))
  379.         CloseDeskAcc(((WindowPeek)window)->windowKind);
  380.     else {
  381.         HideWindow(window);
  382.         if (IsAppWindow(window))
  383.             CloseWindow(window);
  384.         else if (((WindowPeek)window)->windowKind >= dialogKind)
  385.             CloseDialog((DialogPtr)window);
  386.     }
  387. }
  388.  
  389.  
  390.  
  391. /*****************************************************************************/
  392.  
  393.  
  394.  
  395. /* Dispose a window.  This handles desk accessory and application windows.  Use
  396. ** this call (instead of CloseAnyWindow) if you want the memory for the window
  397. ** record to be disposed of.  (Same as CloseWindow v.s. DisposeWindow.) */
  398.  
  399. void    DisposeAnyWindow(WindowPtr window)
  400. {
  401.     if (IsDAWindow(window))
  402.         CloseDeskAcc(((WindowPeek)window)->windowKind);
  403.     else {
  404.         HideWindow(window);
  405.         if (IsAppWindow(window))
  406.             DisposeWindow(window);
  407.         else if (((WindowPeek)window)->windowKind >= dialogKind)
  408.             DisposeDialog((DialogPtr)window);
  409.     }
  410. }
  411.  
  412.  
  413.  
  414. /*****************************************************************************/
  415.  
  416.  
  417.  
  418. /* Display an alert that tells the user an error occurred, then exit the
  419. ** program.  This function is used as an ultimate bail-out for serious errors
  420. ** that prohibit the continuation of the application.  Errors that do not
  421. ** require the termination of the application should be handled in a different
  422. ** manner. */
  423.  
  424. void    DeathAlert(short errResID, short errStringIndex)
  425. {
  426.     ErrorAlert(errResID, errStringIndex);
  427.     ExitToShell();
  428. }
  429.  
  430.  
  431.  
  432. /*****************************************************************************/
  433.  
  434.  
  435.  
  436. /* Display an alert that tells the user an error occurred, then exit the
  437. ** program.  This function is used as an ultimate bail-out for serious errors
  438. ** that prohibit the continuation of the application.  Errors that do not
  439. ** require the termination of the application should be handled in a different
  440. ** manner.  The message parameter is an error code that is to be displayed. */
  441.  
  442. void    DeathAlertMessage(short errResID, short errStringIndex, short message)
  443. {
  444.     ErrorAlertMessage(errResID, errStringIndex, message);
  445.     ExitToShell();
  446. }
  447.  
  448.  
  449.  
  450. /*****************************************************************************/
  451.  
  452.  
  453.  
  454. /* Display an alert that tells the user an error occurred. */
  455.  
  456. void    ErrorAlert(short errResID, short errStringIndex)
  457. {
  458.     ErrorAlertMessage(errResID, errStringIndex, 0);
  459. }
  460.  
  461.  
  462.  
  463. /*****************************************************************************/
  464.  
  465.  
  466.  
  467. /* Display an alert to inform the user of an error.  errStringIndex acts as an
  468. ** index into a STR# resource of error messages.  If no errStringIndex is
  469. ** given, i.e. = 0, then use a standard message.  If message is not noErr then
  470. ** display it as well.
  471. **
  472. ** BUG NOTE:  GetIndString returns a bogus String if the index is
  473. **            not positive. */
  474.  
  475. void    ErrorAlertMessage(short errResID, short errStringIndex, short message)
  476. {
  477.     Str255    msg1, msg2;
  478.  
  479.     SetCursor(&qd.arrow);
  480.  
  481.     if (errStringIndex <= 0) {
  482.         errStringIndex = eStandardErr;
  483.         errResID = rUtilStrings;
  484.     }
  485.     GetIndString(msg1, errResID, errStringIndex);
  486.  
  487.     if (message == noErr) {
  488.         ParamText(msg1, "\p", "\p", "\p");
  489.         CenteredAlert(rUtilErrorAlert, nil, nil);
  490.     } else {
  491.         pcpydec(msg2, message);
  492.         ParamText(msg1, msg2, "\p", "\p");
  493.         CenteredAlert(rUtilErrorMessageAlert, nil, nil);
  494.     }
  495. }
  496.  
  497.  
  498.  
  499. /*****************************************************************************/
  500.  
  501.  
  502.  
  503. /* FindSysFolder returns the (real) vRefNum, and the DirID of the current
  504. ** system folder.  It uses the Folder Manager if present, otherwise it falls
  505. ** back to SysEnvirons.  It returns zero on success, otherwise a standard
  506. ** system error. */
  507.  
  508. OSErr    FindSysFolder(short *foundVRefNum, long *foundDirID)
  509. {
  510.     long            gesResponse;
  511.     SysEnvRec        envRec;
  512.     WDPBRec            myWDPB;
  513.     unsigned char    volName[34];
  514.     OSErr            err;
  515.  
  516.     *foundVRefNum = 0;
  517.     *foundDirID = 0;
  518.     if (!Gestalt(gestaltFindFolderAttr, &gesResponse) &&
  519.         BTstQ(gesResponse, gestaltFindFolderPresent)) {        /* Does Folder Manager exist? */
  520.             err = FindFolder(kOnSystemDisk, kSystemFolderType, kDontCreateFolder,
  521.                 foundVRefNum, foundDirID);
  522.     } else {
  523.         /* Gestalt can't give us the answer, so we resort to SysEnvirons */
  524.         if (!(err = SysEnvirons(curSysEnvVers, &envRec))) {
  525.             myWDPB.ioVRefNum = envRec.sysVRefNum;
  526.             volName[0] = '\000';                    /* Zero volume name */
  527.             myWDPB.ioNamePtr = volName;
  528.             myWDPB.ioWDIndex = 0;
  529.             myWDPB.ioWDProcID = 0;
  530.             if (!(err = PBGetWDInfo(&myWDPB, 0))) {
  531.                 *foundVRefNum = myWDPB.ioWDVRefNum;
  532.                 *foundDirID = myWDPB.ioWDDirID;
  533.             }
  534.         }
  535.     }
  536.     return(err);
  537. }
  538.  
  539.  
  540.  
  541. /*****************************************************************************/
  542.  
  543.  
  544.  
  545. /* GetAppIndResource gets a resource from the application's resource file
  546. ** by index. */
  547.  
  548. Handle    GetAppIndResource(ResType theType, short index, OSErr *err)
  549. {
  550.     short    savedResFile;
  551.     Handle    returnHandle;
  552.  
  553.     savedResFile = CurResFile();
  554.     UseResFile(gAppResRef);
  555.     returnHandle = Get1IndResource(theType, index);
  556.     if (err) *err = ResError();
  557.     UseResFile(savedResFile);
  558.     return(returnHandle);
  559. }
  560.  
  561.  
  562.  
  563. /*****************************************************************************/
  564.  
  565.  
  566.  
  567. /* GetAppNamedResource gets a resource from the application's resource file
  568. ** by name. */
  569.  
  570. Handle    GetAppNamedResource(ResType theType, StringPtr name, OSErr *err)
  571. {
  572.     short    savedResFile;
  573.     Handle    returnHandle;
  574.  
  575.     savedResFile = CurResFile();
  576.     UseResFile(gAppResRef);
  577.     returnHandle = Get1NamedResource(theType, name);
  578.     if (err) *err = ResError();
  579.     UseResFile(savedResFile);
  580.     return(returnHandle);
  581. }
  582.  
  583.  
  584.  
  585. /*****************************************************************************/
  586.  
  587.  
  588.  
  589. /* GetAppResource gets a resource from the application's resource file by
  590. ** resource ID. */
  591.  
  592. Handle    GetAppResource(ResType theType, short theID, OSErr *err)
  593. {
  594.     short    savedResFile;
  595.     Handle    returnHandle;
  596.  
  597.     savedResFile = CurResFile();
  598.     UseResFile(gAppResRef);
  599.     returnHandle = Get1Resource(theType, theID);
  600.     if (err) *err = ResError();
  601.     UseResFile(savedResFile);
  602.     return(returnHandle);
  603. }
  604.  
  605.  
  606.  
  607. /*****************************************************************************/
  608.  
  609.  
  610.  
  611. /* Checks for the presence of A/UX by whatever means is appropriate.  Returns
  612. ** the major version number of A/UX (i.e. 0 if A/UX is not present, 1 for
  613. ** any 1.x.x version 2 for any 2.x version, etc.
  614. **
  615. ** This code should work for all past, present and future A/UX systems. */
  616.  
  617. #define HWCfgFlags    0xB22    /* Low memory global used to check if A/UX is running */
  618.  
  619. short    GetAUXVersion(void)
  620. {
  621.     long    auxVersion;
  622.     short    err;
  623.     short    *flagPtr;
  624.  
  625.     /* This code assumes the Gestalt glue checks for the presence of the _Gestalt
  626.     ** trap and does something intelligent if the trap is unavailable, i.e.
  627.     ** return unknown selector. */
  628.  
  629.     auxVersion = 0;
  630.     err = Gestalt(gestaltAUXVersion, &auxVersion);
  631.  
  632.     /* If gestaltUnknownErr or gestaltUndefSelectorErr was returned, then either
  633.     ** we weren't running on A/UX, or the _Gestalt trap is unavailable so use
  634.     ** HWCfgFlags instead.
  635.     ** All other errors are ignored (implies A/UX not present). */
  636.  
  637.     if (err == gestaltUnknownErr || err == gestaltUndefSelectorErr) {    /* Use HWCfgFlags */
  638.         flagPtr = (short *) HWCfgFlags;
  639.         if (BTstQ(*flagPtr, 9))
  640.             auxVersion = 0x100;            /* Do Have A/UX, so assume version 1.x.x */
  641.     }
  642.  
  643.     /* Now right shift auxVersion by 8 bits to get major version number. */
  644.  
  645.     auxVersion >>= 8;
  646.     return((short)auxVersion);
  647. }
  648.  
  649.  
  650.  
  651. /*****************************************************************************/
  652.  
  653.  
  654.  
  655. OSErr    SimpleCanDialog(void)
  656. {
  657.     OSErr                err;
  658.     ProcessSerialNumber    cpsn, fpsn;
  659.     Boolean                procsSame;
  660.  
  661.     err = noErr;
  662.     if (gSystemVersion >= 0x0700) {
  663.         err = AEInteractWithUser(kAEDefaultTimeout, nil, nil);
  664.             /* Ask the AppleEvent Manager if we can come forward */
  665.         GetCurrentProcess(&cpsn);        /* We may have been moved to the front. */
  666.         GetFrontProcess(&fpsn);
  667.         SameProcess(&cpsn, &fpsn, &procsSame);
  668.         gInBackground = !procsSame;
  669.     }
  670.  
  671. /* Three results are possible here....
  672. **   noErr
  673. **     If the call completes with noErr, you can assume that you are
  674. **     (or have been made) the frontmost application, and you are free
  675. **     to interact with the user as much as you'd like.  Put up dialogs,
  676. **     flash alerts, whatever.
  677. **     If you were already in the foreground, AEInteractWithUser
  678. **     immediatly returns with a noErr, so you _should_ always call it.
  679. **
  680. **   errAETimeout
  681. **     If you pass a timeout value, or kAEDefaultTimeout, it is possible
  682. **     for the AEInteractWithUser call to timeout and return control to
  683. **     you before any state change has happened, you are still in the background.
  684. **     What you do at this point is a design decision you'll have to make.
  685. **     You can re-post the AEInteract call, perhaps with a larger timeout
  686. **     or kNoTimeOut, and see if you come forward this time.
  687. **     Or, you can continue on knowing that you are in the background and
  688. **     not interact at all.
  689. **
  690. **   errAENoUserInteraction
  691. **     If you get this error code back, this means that you
  692. **     MUST NOT interact with the user.  Do NOT put up any dialogs, alerts,
  693. **     or cause any other action that requires direct user intervention.
  694. **     This error code will be returned, for example, if any application
  695. **     has used the AESetInteractionAllowed call to specify no interaction,
  696. **     or if there is a pending AppleEvent that has interaction denied.
  697. **     This will also be returned if your application is being run by
  698. **     a script system, since an AppleEvent script cannot press buttons.
  699. **     By the way, if this is the case the AEinteractWithUser call has
  700. **     also not posted the notification.
  701. */
  702.  
  703.     return(err);
  704. }
  705.  
  706.  
  707.  
  708. /*****************************************************************************/
  709.  
  710.  
  711.  
  712. /* Given a dialog ID and a window pointer the dialog relates to, this function
  713. ** will center the dialog’s rectangle before showing it on the proper screen.
  714. ** This follows the Apple Human Interface Guidelines for where to place a
  715. ** centered window on the screen.  If the dialog is not closely associated with
  716. ** another window, pass a nil for the window pointer of the related window.  If
  717. ** you pass a nil, the dialog is simply displayed where the resource
  718. ** would indicate. */
  719.  
  720. DialogPtr    GetCenteredDialog(short id, DialogPtr storage, WindowPtr relatedWindow, WindowPtr behind)
  721. {
  722.     DialogTHndl    dlogResource;
  723.     DialogPtr    dialog;
  724.     Boolean        oldVis;
  725.     char        hstate;
  726.     OSErr        err;
  727.     Rect        sizeInfo;
  728.  
  729.     dialog = nil;
  730.     if (!SimpleCanDialog()) {
  731.         dlogResource = (DialogTHndl)GetAppResource('DLOG', id, &err);
  732.         if (dlogResource) {
  733.             hstate = LockHandleHigh((Handle)dlogResource);
  734.             oldVis = (*dlogResource)->visible;
  735.             (*dlogResource)->visible = false;
  736.             dialog = GetNewDialog(id, storage, behind);
  737.             if (dialog) {
  738.                 SetRect(&sizeInfo, 0, 0, 0, 0);
  739.                 CenterWindow(dialog, relatedWindow, sizeInfo);
  740.                 if (oldVis)
  741.                     ShowWindow(dialog);
  742.             }
  743.             dlogResource = (DialogTHndl)GetAppResource('DLOG', id, &err);
  744.             if (dlogResource) {
  745.                 (*dlogResource)->visible = oldVis;
  746.                 HSetState((Handle)dlogResource, hstate);
  747.             }
  748.         }
  749.     }
  750.     return(dialog);
  751. }
  752.  
  753.  
  754.  
  755. /*****************************************************************************/
  756.  
  757.  
  758.  
  759. /* Given a window ID and a window pointer the window relates to, this function
  760. ** will center the window’s rectangle before showing it on the proper screen.
  761. ** This follows the Apple Human Interface Guidelines for where to place a
  762. ** centered window on the screen.  If the window is not closely associated with
  763. ** another window, pass a nil for the window pointer of the related window.  If
  764. ** you pass a nil, the window is simply displayed where the resource
  765. ** would indicate. */
  766.  
  767. WindowPtr    GetCenteredWindow(short id, Ptr storage, Boolean vis, WindowPtr relWindow,
  768.                               WindowPtr behind, Boolean inColor, Rect sizeInfo, long refCon)
  769. {
  770.     return(GetSomeKindOfWindow(CenterWindow, id, storage, vis, relWindow,
  771.                                behind, inColor, sizeInfo, refCon));
  772. }
  773.  
  774.  
  775.  
  776. /*****************************************************************************/
  777.  
  778.  
  779.  
  780. /* GetGestaltResult returns the result value from Gestalt for the specified
  781. ** selector.  If Gestalt returned an error GetGestaltResult returns zero.
  782. ** Use of this function is only cool if we don't care whether Gestalt returned
  783. ** an error.  In many cases you may need to know the exact Gestalt error code
  784. ** so then this function would be inappropriate.
  785. ** See GetAUXVersion for an example. */
  786.  
  787. long    GetGestaltResult(OSType gestaltSelector)
  788. {
  789.     long    gestaltResult;
  790.  
  791.     if (Gestalt(gestaltSelector, &gestaltResult) == noErr)
  792.         return(gestaltResult);
  793.     else
  794.         return(0);
  795. }
  796.  
  797.  
  798.  
  799. /*****************************************************************************/
  800.  
  801.  
  802.  
  803. /* Get the global coordinates of the mouse. */
  804.  
  805. Point    GetGlobalMouse(void)
  806. {
  807.     WindowPtr    oldPort, wmPort;
  808.     Point        pt;
  809.  
  810.     GetPort(&oldPort);
  811.     GetWMgrPort(&wmPort);
  812.     SetPort(wmPort);
  813.     GetMouse(&pt);
  814.     LocalToGlobal(&pt);
  815.     SetPort(oldPort);
  816.     return(pt);
  817. }
  818.  
  819.  
  820.  
  821. /*****************************************************************************/
  822.  
  823.  
  824.  
  825. /* Given a window, this will return the top left point of the window’s port in
  826. ** global coordinates.  Something this doesn’t include is the window’s drag
  827. ** region (or title bar).  This returns the top left point of the window’s
  828. ** content area only. */
  829.  
  830. Point    GetGlobalTopLeft(WindowPtr window)
  831. {
  832.     GrafPtr    oldPort;
  833.     Point    globalPt;
  834.  
  835.     GetPort(&oldPort);
  836.     SetPort(window);
  837.     globalPt = TopLeft(window->portRect);
  838.     LocalToGlobal(&globalPt);
  839.     SetPort(oldPort);
  840.     return(globalPt);
  841. }
  842.  
  843.  
  844.  
  845. /*****************************************************************************/
  846.  
  847.  
  848.  
  849. /* Return the amount of free space on the volume in KBytes. -1 is returned as
  850. ** the size if there is an error. */
  851.  
  852. long    GetKFreeSpace(short vRefNum)
  853. {
  854.     HParamBlockRec    pb;
  855.     OSErr            err;
  856.  
  857.     pb.volumeParam.ioNamePtr = nil;            /* we don't care about the name */
  858.     pb.volumeParam.ioVRefNum = vRefNum;
  859.     pb.volumeParam.ioVolIndex = 0;            /* use ioVRefNum only */
  860.     err = PBHGetVInfo(&pb, false);
  861.  
  862.     if (err == noErr)
  863.         return((pb.volumeParam.ioVFrBlk * pb.volumeParam.ioVAlBlkSiz) / 1024);
  864.     else
  865.         return(-1);
  866. }
  867.  
  868.  
  869.  
  870. /*****************************************************************************/
  871.  
  872.  
  873.  
  874. Rect    GetMainScreenRect(void)
  875. {
  876.     GDHandle    mainDevice;
  877.     GrafPtr        mainPort;
  878.  
  879.     if (gQDVersion > kQDOriginal) {
  880.         mainDevice = GetMainDevice();
  881.         return((*mainDevice)->gdRect);
  882.     }
  883.     else {
  884.         GetWMgrPort(&mainPort);
  885.         return(mainPort->portRect);
  886.     }
  887. }
  888.  
  889.  
  890.  
  891. /*****************************************************************************/
  892.  
  893.  
  894.  
  895. /* Find the greatest overlap device for the given global rectangle. */
  896.  
  897. GDHandle    GetRectDevice(Rect globalRect)
  898. {
  899.     long        area, maxArea;
  900.     GDHandle    device, deviceToReturn;
  901.     Rect        intersection;
  902.  
  903.     deviceToReturn = GetMainDevice();            /* Use as default choice. */
  904.     maxArea = 0;
  905.  
  906.     for (device = GetDeviceList(); device; device = GetNextDevice(device)) {
  907.         if (TestDeviceAttribute(device, screenDevice)
  908.           && TestDeviceAttribute(device, screenActive)
  909.           && SectRect(&globalRect, &((*device)->gdRect), &intersection)) {
  910.             area = ((long)(intersection.right - intersection.left)) *
  911.                    ((long)(intersection.bottom - intersection.top));
  912.             if (area > maxArea) {
  913.                 deviceToReturn = device;
  914.                 maxArea = area;
  915.             }
  916.         }
  917.     }
  918.     return(deviceToReturn);
  919. }
  920.  
  921.  
  922.  
  923. /*****************************************************************************/
  924.  
  925.  
  926.  
  927. /* Find the rect of the greatest overlap device for the given global rect. */
  928.  
  929. Rect    GetRectDeviceRect(Rect globalRect)
  930. {
  931.     if (gQDVersion > kQDOriginal)
  932.         return((*GetRectDevice(globalRect))->gdRect);
  933.     else
  934.         return(GetMainScreenRect());
  935. }
  936.  
  937.  
  938.  
  939. /*****************************************************************************/
  940.  
  941.  
  942.  
  943. /* Given a window positioning procedure pointer, a window ID and a window
  944. ** pointer the window relates to, this function open a new window by either
  945. ** a NewCWindow or a NewWindow call, depending on the value of inColor.  The
  946. ** window will be opened invisible, independent of what the resource says.
  947. ** Once the window is opened successfully, the positioning procedure is
  948. ** called.  The positioning procedure is passed a pointer to the just-opened
  949. ** invisible window and a pointer to the related window.  It is up to the
  950. ** positioning procedure to move the invisible window to the correct location
  951. ** on the correct device.  Once the positioning procedure returns, the window
  952. ** will be made visible if so indicated by the resource. */
  953.  
  954. WindowPtr    GetSomeKindOfWindow(PositionWndProcPtr whatKind, short windID, Ptr storage,
  955.                                 Boolean vis, WindowPtr relatedWindow, WindowPtr behind,
  956.                                 Boolean inColor, Rect sizeInfo, long refCon)
  957. {
  958.     WindowTHndl        windowResource;
  959.     WindowTemplate    wt;
  960.     WindowPtr        window;
  961.     PaletteHandle    wpalette;
  962.     CTabHandle        wcolor;
  963.     Ptr                allocStg;
  964.     OSErr            err;
  965.  
  966.     gGetWindowErr = noErr;
  967.  
  968.     window = nil;        /* Assume we will fail.  (Good attitude.) */
  969.     SetRect(&gOpenedWindowTemplate.boundsRect, 0, 0, 0, 0);
  970.  
  971.     if (gQDVersion == kQDOriginal)
  972.         inColor = false;
  973.  
  974.     if (!(allocStg = storage))
  975.         if (!(allocStg = NewPtr(sizeof(WindowRecord))))
  976.             gGetWindowErr = memFullErr;
  977.  
  978.     if (allocStg) {            /* If we have memory for the window record... */
  979.  
  980.         wt = gWindowTemplate;
  981.         if (EmptyRect(&wt.boundsRect)) {
  982.             windowResource = (WindowTHndl)GetAppResource('WIND', windID, &err);
  983.             if (windowResource)
  984.                 wt = **windowResource;        /* Make local copy of resource. */
  985.             else
  986.                 gGetWindowErr = resNotFound;
  987.         }
  988.  
  989.         if (!EmptyRect(&wt.boundsRect)) {
  990.             window = (inColor ? NewCWindow(allocStg, &wt.boundsRect,
  991.                                            wt.title, false, wt.procID,
  992.                                            behind, wt.goAwayFlag, wt.refCon)
  993.                                : NewWindow(allocStg, &wt.boundsRect, wt.title,
  994.                                            false, wt.procID,
  995.                                            behind, wt.goAwayFlag, wt.refCon));
  996.                 /* Open either a regular or color window. */
  997.  
  998.             if (window) {        /* If we were able to open a window... */
  999.                 if (inColor) {
  1000.                     wpalette = GetNewPalette(windID);
  1001.                     if (wpalette)
  1002.                         SetPalette(window, wpalette, true);
  1003.                     wcolor = (CTabHandle)GetResource('wctb', windID);
  1004.                     if (wcolor)
  1005.                         SetWinColor(window, (WCTabHandle)wcolor);
  1006.                 }
  1007.  
  1008.                 SetWRefCon(window, refCon);
  1009.                 if (whatKind)
  1010.                     (*whatKind)(window, relatedWindow, sizeInfo);
  1011.                         /* Call the designated window positioning procedure. */
  1012.  
  1013.                 if (vis)
  1014.                     ShowWindow(window);
  1015.                         /* If caller says window should be visible, make it so. */
  1016.             }
  1017.         }
  1018.         if (!window) {
  1019.             if (allocStg != storage)
  1020.                 DisposePtr(storage);
  1021.         }            /* If we failed, then get rid of window record memory. */
  1022.         else
  1023.             gOpenedWindowTemplate = wt;
  1024.     }
  1025.  
  1026.     return(window);
  1027. }
  1028.  
  1029.  
  1030.  
  1031. /*****************************************************************************/
  1032.  
  1033.  
  1034.  
  1035. /* Given a window ID and a window pointer the window relates to, this function
  1036. ** will stagger the window’s rectangle before showing it on the proper screen.
  1037. ** This follows the Apple Human Interface Guidelines for where to place a
  1038. ** staggered window on the screen.  If the window is not closely associated
  1039. ** with another window, pass a nil for the window pointer of the related
  1040. ** window.  If you pass a nil, the window is simply displayed where the
  1041. ** resource would indicate. */
  1042.  
  1043. WindowPtr    GetStaggeredWindow(short id, Ptr storage, Boolean vis, WindowPtr relWindow,
  1044.                                WindowPtr behind, Boolean inColor, Rect sizeInfo, long refCon)
  1045. {
  1046.     return(GetSomeKindOfWindow(StaggerWindow, id, storage, vis, relWindow,
  1047.                                behind, inColor, sizeInfo, refCon));
  1048. }
  1049.  
  1050.  
  1051.  
  1052. /*****************************************************************************/
  1053.  
  1054.  
  1055.  
  1056. /*    Check the bits of a trap number to determine its type. */
  1057.  
  1058. TrapType    GetTrapType(short theTrap)
  1059. {
  1060.     /* OS traps start with A0, Tool with A8 or AA. */
  1061.     if ((theTrap & 0x0800) == 0)                    /* per D.A. */
  1062.         return(OSTrap);
  1063.     else
  1064.         return(ToolTrap);
  1065. }
  1066.  
  1067.  
  1068.  
  1069. /*****************************************************************************/
  1070.  
  1071.  
  1072.  
  1073. /* Given a window pointer, return the global rectangle that encloses the
  1074. ** content area of the window. */
  1075.  
  1076. Rect    GetWindowContentRect(WindowPtr window)
  1077. {
  1078.     WindowPtr    oldPort;
  1079.     Rect        contentRect;
  1080.  
  1081.     SetRect(&contentRect, 0, 0, 0, 0);
  1082.     if (window) {
  1083.         GetPort(&oldPort);
  1084.         SetPort(window);
  1085.         contentRect = window->portRect;
  1086.         LocalToGlobalRect(&contentRect);
  1087.         SetPort(oldPort);
  1088.     }
  1089.  
  1090.     return(contentRect);
  1091. }
  1092.  
  1093.  
  1094.  
  1095. /*****************************************************************************/
  1096.  
  1097.  
  1098.  
  1099. /* This procedure counts the number of windows in the application plane.
  1100. ** You have the choices of also including DAs and invisible windows in
  1101. ** this count. */
  1102.  
  1103. short    GetWindowCount(Boolean includeDAs, Boolean includeDLOGs, Boolean includeInvisibles)
  1104. {
  1105.     WindowPeek    window;
  1106.     short        count;
  1107.  
  1108.     for (count = 0, window = LMGetWindowList(); (window != nil); window = window->nextWindow) {
  1109.         if ((window->windowKind < 0) && (!includeDAs)) continue;
  1110.         if ((window->windowKind == dialogKind) && (!includeDLOGs)) continue;
  1111.         if ((window->visible) || (includeInvisibles))
  1112.             count++;
  1113.     }
  1114.     return(count);
  1115. }
  1116.  
  1117.  
  1118.  
  1119. /*****************************************************************************/
  1120.  
  1121.  
  1122.  
  1123. /* Find the greatest overlap device for the given window. */
  1124.  
  1125. GDHandle    GetWindowDevice(WindowPtr window)
  1126. {
  1127.     return(GetRectDevice(GetWindowStructureRect(window)));
  1128. }
  1129.  
  1130.  
  1131.  
  1132. /*****************************************************************************/
  1133.  
  1134.  
  1135.  
  1136. /* Given a window pointer, find the device that contains most of the window
  1137. ** and return the device's bounding rectangle. */
  1138.  
  1139. Rect    GetWindowDeviceRect(WindowPtr window)
  1140. {
  1141.     if (gQDVersion > kQDOriginal)
  1142.         return((*GetWindowDevice(window))->gdRect);
  1143.     else
  1144.         return(GetMainScreenRect());
  1145. }
  1146.  
  1147.  
  1148.  
  1149. /*****************************************************************************/
  1150.  
  1151.  
  1152.  
  1153. /* Given a window pointer, find the device that contains most of the window
  1154. ** and return the device's bounding rectangle.  If this device is the main
  1155. ** device, then remove the menubar area from the rectangle. */
  1156.  
  1157. Rect    GetWindowDeviceRectNMB(WindowPtr window)
  1158. {
  1159.     Rect    deviceRect, tempRect;
  1160.  
  1161.     SetRect(&deviceRect, 0, 0, 0, 0);
  1162.  
  1163.     if (window) {
  1164.         deviceRect = GetWindowDeviceRect(window);
  1165.         tempRect = GetMainScreenRect();
  1166.         if (EqualRect(&deviceRect, &tempRect))
  1167.             deviceRect.top += GetMBarHeight();
  1168.     }
  1169.  
  1170.     return(deviceRect);
  1171. }
  1172.  
  1173.  
  1174.  
  1175. /*****************************************************************************/
  1176.  
  1177.  
  1178.  
  1179. /* This procedure is used to get the rectangle that surrounds the entire
  1180. ** structure of a window.  This is true whether or not the window is visible.
  1181. ** If the window is visible, then it is a simple matter of using the bounding
  1182. ** rectangle of the structure region.  If the window is invisible, then the
  1183. ** strucRgn is not correct.  To make it correct, then window has to be moved
  1184. ** way off the screen and then made visible.  This generates a valid strucRgn,
  1185. ** although it is valid for the position that is way off the screen.  It still
  1186. ** needs to be offset back into the original position.  Once the bounding
  1187. ** rectangle for the strucRgn is obtained, the window can then be hidden again
  1188. ** and moved back to its correct location.  Note that ShowHide is used,
  1189. ** instead of ShowWindow and HideWindow.  HideWindow can change the plane of
  1190. ** the window.  Also, ShowHide does not affect the hiliting of windows.
  1191. ** Note that using ShowHide to make the window visible has the unfortunate
  1192. ** side-effect of changing the userState rect.  Since we make the window
  1193. ** invisible prior to moving it back, userState gets left funky.  Due to this,
  1194. ** we have to cache it prior to doing the ShowHide games. */
  1195.  
  1196. Rect    GetWindowStructureRect(WindowPtr window)
  1197. {
  1198. #define kOffscreenLoc 0x4000
  1199.  
  1200.     GrafPtr    oldPort;
  1201.     Rect    structureRect, userState;
  1202.     Point    windowLoc;
  1203.  
  1204.     SetRect(&structureRect, 0, 0, 0, 0);
  1205.  
  1206.     if (window) {
  1207.  
  1208.         if (((WindowPeek)window)->visible)
  1209.             structureRect = (*(((WindowPeek)window)->strucRgn))->rgnBBox;
  1210.  
  1211.         else {
  1212.             GetPort(&oldPort);
  1213.             SetPort(window);
  1214.             windowLoc  = GetGlobalTopLeft(window);
  1215.             if (((WindowPeek)window)->spareFlag)
  1216.                 userState = (*(WStateDataHandle)(((WindowPeek)window)->dataHandle))->userState;
  1217.             MoveWindow(window, kOffscreenLoc, kOffscreenLoc, false);
  1218.             ShowHide(window, true);
  1219.             structureRect = (*(((WindowPeek)window)->strucRgn))->rgnBBox;
  1220.             ShowHide(window, false);
  1221.             MoveWindow(window, windowLoc.h, windowLoc.v, false);
  1222.             if (((WindowPeek)window)->spareFlag)
  1223.                 (*(WStateDataHandle)(((WindowPeek)window)->dataHandle))->userState = userState;
  1224.             SetPort(oldPort);
  1225.             OffsetRect(&structureRect, windowLoc.h - kOffscreenLoc, windowLoc.v - kOffscreenLoc);
  1226.         }
  1227.     }
  1228.  
  1229.     return(structureRect);
  1230. }
  1231.  
  1232.  
  1233.  
  1234. /*****************************************************************************/
  1235.  
  1236.  
  1237.  
  1238. void    GlobalToLocalRect(Rect *aRect)
  1239. {
  1240.     GlobalToLocal(&TopLeft(*aRect));
  1241.     GlobalToLocal(&BotRight(*aRect));
  1242. }
  1243.  
  1244.  
  1245.  
  1246. /*****************************************************************************/
  1247.  
  1248.  
  1249.  
  1250. void    InitToolBox(void)
  1251. {
  1252.     InitGraf((Ptr) &qd.thePort);
  1253.     InitFonts();
  1254.     InitWindows();
  1255.     InitMenus();
  1256.     TEInit();
  1257.     InitDialogs(0);
  1258.     InitCursor();
  1259. }
  1260.  
  1261.  
  1262.  
  1263. /*****************************************************************************/
  1264.  
  1265.  
  1266.  
  1267. /* GetSystemInfo sets up some global variables for use by the utilities
  1268. ** package and your application.  If you call StandardInitialization, you
  1269. ** don't need to call this, as it will do it for you. */
  1270.  
  1271. void    GetSystemInfo(void)
  1272. {
  1273.     Handle            bndlResource;
  1274.     OSErr            err;
  1275.     short            ignoreRefNum;
  1276. #ifndef powerc
  1277.     Handle            apParam;
  1278. #endif
  1279.  
  1280.     if (!gHaveSystemInfo) {
  1281.  
  1282.         /* Init all the Gestalt variables */
  1283.         gMachineType   = GetGestaltResult(gestaltMachineType);
  1284.         gSystemVersion = GetGestaltResult(gestaltSystemVersion);
  1285.         gProcessorType = GetGestaltResult(gestaltProcessorType);
  1286.  
  1287.         /* We only concern ourselves with there being an FPU, not which type it is. */
  1288.         gHasFPU = (GetGestaltResult(gestaltFPUType) != gestaltNoFPU);
  1289.  
  1290.         /* We only concern ourselves with the major QD version number
  1291.         ** 0 for original QD, 1 for 8-bit color QD, and 2 for 32-bit QD. */
  1292.  
  1293.         gQDVersion = (GetGestaltResult(gestaltQuickdrawVersion) >> 8) & 0xFF;
  1294.         gKeyboardType = GetGestaltResult(gestaltKeyboardType);
  1295.  
  1296.         if (!OpenDriver("\p.MPP", &ignoreRefNum))
  1297.             gAppleTalkVersion = GetGestaltResult(gestaltAppleTalkVersion);
  1298.                 /* Under system 6, the driver isn't necessarily open, so open it for sure.
  1299.                 ** If the driver isn't opened, then the gestalt selector isn't installed,
  1300.                 ** and therefore returns 0, which isn't really the case. */
  1301.  
  1302.         /* We only concern ourselves with there being an PMMU, not which type it is. */
  1303.         gHasPMMU = GetGestaltResult(gestaltMMUType) >= gestalt68851;
  1304.         gAUXVersion = GetAUXVersion();
  1305.  
  1306.         gHasWaitNextEvent = TrapExists(_WaitNextEvent);
  1307.         gInBackground = false;
  1308.  
  1309.         /* PowerPC doesn't support GetAppParms for native code (use AppleEvents!!!), so we find 
  1310.         ** the information in other ways. */
  1311. #ifdef powerc
  1312.         {
  1313.             ProcessSerialNumber        currentPSN;
  1314.             ProcessInfoRec            currentProcRec;
  1315.  
  1316.             /* It's safe to assume we have a Process Manager on PowerPC */
  1317.             GetCurrentProcess (¤tPSN);
  1318.             currentProcRec.processInfoLength = sizeof(currentProcRec);
  1319.             currentProcRec.processName = gAppName;
  1320.             currentProcRec.processAppSpec = nil;
  1321.             GetProcessInformation (¤tPSN, ¤tProcRec);
  1322.             gAppResRef = CurResFile();            /* This is lazy and assumes no one has mucked with the resource chain */
  1323.         }
  1324. #else
  1325.         GetAppParms(gAppName, &gAppResRef, &apParam);
  1326. #endif
  1327.  
  1328. #ifdef THINK_C
  1329.         gAppResRef = CurResFile();            /* returns refNum of .rsrc file */
  1330.             /* 10/16/90 pvh/MacDTS
  1331.             ** With GetAppParams(), THINK C in project mode returns the project resource
  1332.             ** file AND NOT the .rsrc file, which is what one really wants (trust me).
  1333.             ** If THINK is present we will return CurResFile() which will be the .rsrc
  1334.             ** file instead.  The name will still be the project name in project mode,
  1335.             ** so be aware of that. */
  1336. #endif
  1337.  
  1338.         bndlResource = GetAppIndResource('BNDL', 1, &err);
  1339.         if (bndlResource)
  1340.             gSignature = *(OSType *)(*bndlResource);
  1341.  
  1342.         gHaveSystemInfo = true;
  1343.     }
  1344. }
  1345.  
  1346.  
  1347.  
  1348. /*****************************************************************************/
  1349.  
  1350.  
  1351.  
  1352. /* Check to see if a window belongs to the application.  If the window pointer
  1353. ** passed was nil, then it could not be an application window.  WindowKinds
  1354. ** that are negative belong to the system and windowKinds less than userKind
  1355. ** are reserved by Apple except for windowKinds equal to dialogKind, which
  1356. ** mean it is a dialog. */
  1357.  
  1358. Boolean    IsAppWindow(WindowPtr window)
  1359. {
  1360.     if (window) return(((WindowPeek)window)->windowKind >= userKind);
  1361.     else        return(false);
  1362. }
  1363.  
  1364.  
  1365.  
  1366. /*****************************************************************************/
  1367.  
  1368.  
  1369.  
  1370. /* Check to see if a window belongs to a desk accessory. */
  1371.  
  1372. Boolean    IsDAWindow(WindowPtr window)
  1373. {
  1374.     if (window)    /* DA windows have negative windowKinds */
  1375.         return(((WindowPeek) window)->windowKind < 0);
  1376.     else
  1377.         return(false);
  1378. }
  1379.  
  1380.  
  1381.  
  1382. /*****************************************************************************/
  1383.  
  1384.  
  1385.  
  1386. void    LocalToGlobalRect(Rect *aRect)
  1387. {
  1388.     LocalToGlobal(&TopLeft(*aRect));
  1389.     LocalToGlobal(&BotRight(*aRect));
  1390. }
  1391.  
  1392.  
  1393.  
  1394. /*****************************************************************************/
  1395.  
  1396.  
  1397.  
  1398. char    LockHandleHigh(Handle theHandle)
  1399. {
  1400.     char    hstate;
  1401.  
  1402.     hstate = HGetState(theHandle);
  1403.     MoveHHi(theHandle);
  1404.     HLock(theHandle);
  1405.     return(hstate);
  1406. }
  1407.  
  1408.  
  1409.  
  1410. /*****************************************************************************/
  1411.  
  1412.  
  1413.  
  1414. /* InitGraf is always implemented (trap $A86E).  If the trap table is big
  1415. ** enough, trap $AA6E will always point to either Unimplemented or some other
  1416. ** trap, but will never be the same as InitGraf.  Thus, you can check the size
  1417. ** of the trap table by asking if the address of trap $A86E is the same as
  1418. ** $AA6E. */
  1419.  
  1420. short    NumToolboxTraps(void)
  1421. {
  1422.     if (NGetTrapAddress(_InitGraf, ToolTrap) == NGetTrapAddress(0xAA6E, ToolTrap))
  1423.         return(0x200);
  1424.     else
  1425.         return(0x400);
  1426. }
  1427.  
  1428.  
  1429.  
  1430. /*****************************************************************************/
  1431.  
  1432.  
  1433.  
  1434. /* Given two rectangles, this function positions the second within the first
  1435. ** one so that it maintains the spacing specified by the horzRatio and
  1436. ** vertRatio parameters.  In other words, to center an inner rectangle
  1437. ** hoizontally, but have its center be 1/3 from the top of the outer rectangle,
  1438. ** call this function with horzRatio = FixRatio(1, 2), vertRatio =
  1439. ** FixRatio(1, 3).  We use Fixed rather than floating point to avoid
  1440. ** complications when mixing MC68881/non-MC68881 versions of Utilities. */
  1441.  
  1442. void    PositionRectInRect(Rect outerRect, Rect *innerRect, Fixed horzRatio, Fixed vertRatio)
  1443. {
  1444.     short    outerRectHeight;
  1445.     short    outerRectWidth;
  1446.     short    innerRectHeight;
  1447.     short    innerRectWidth;
  1448.     short    yLocation;
  1449.     short    xLocation;
  1450.  
  1451.     outerRectHeight = outerRect.bottom - outerRect.top;
  1452.     outerRectWidth = outerRect.right - outerRect.left;
  1453.  
  1454.     innerRectHeight = innerRect->bottom - innerRect->top;
  1455.     innerRectWidth = innerRect->right - innerRect->left;
  1456.         yLocation = Fix2Long(FixMul(Long2Fix(outerRectHeight - innerRectHeight), vertRatio))
  1457.             + outerRect.top;
  1458.         xLocation = Fix2Long(FixMul(Long2Fix(outerRectWidth - innerRectWidth), horzRatio))
  1459.             + outerRect.left;
  1460.  
  1461.     innerRect->top = yLocation;
  1462.     innerRect->left = xLocation;
  1463.     innerRect->bottom = yLocation + innerRectHeight;
  1464.     innerRect->right = xLocation + innerRectWidth;
  1465. }
  1466.  
  1467.  
  1468.  
  1469. /*****************************************************************************/
  1470.  
  1471.  
  1472.  
  1473. void    PullApplicationToFront(void)
  1474. {
  1475. #define kBroughtToFront 3
  1476.  
  1477.     EventRecord event;
  1478.     short        count;
  1479.  
  1480.     for (count = 1; count <= kBroughtToFront; count++)
  1481.         EventAvail(everyEvent, &event);
  1482. }
  1483.  
  1484.  
  1485.  
  1486. /*****************************************************************************/
  1487.  
  1488.  
  1489.  
  1490. /* This algorithm for staggering windows does quite a good job.  It also is
  1491. ** quite gnarly.  Here's the deal:
  1492. ** There are pre-designated positions that we will try when positioning a
  1493. ** window.  These slots will be tried from the upper-left corner towards the
  1494. ** lower-right corner.  If there are other windows in that slot, then we will
  1495. ** consider that slot taken, and proceed to the next slot.  A slot is
  1496. ** determined to be taken by checking a point with a slop area.  This slop
  1497. ** area is diamond-shaped, not simply rectangular.  If there is no other
  1498. ** visible window with an upper-left corner within the slopt diamond, then
  1499. ** we are allowed to position our window there.
  1500. ** The above rule holds true unless this forces the window to be partly
  1501. ** off the screen.  If the window ends up partly off the screen, then we try
  1502. ** a new diagonal just below the first diagonal we tried.  We keep trying
  1503. ** lower and lower diagonals until we find a spot for the window, or the
  1504. ** diagonal doesn't fit on the screen at all.  If the diagonal doesn't fit,
  1505. ** then we try diagonals to the right of the first diagonal.  If even this
  1506. ** doesn't work, then we give up and put the window in the original spot
  1507. ** we tried. */
  1508.  
  1509. Rect    StaggerWindow(WindowPtr window, WindowPtr relatedWindow, Rect sizeInfo)
  1510. {
  1511.     WindowPtr    whichDevice, staggerFromWindow;
  1512.     Rect        deviceRect, oldWindowRect, newWindowRect, slot1;
  1513.     Rect        testRct1, testRct2, contentRect, staggerFromRect;
  1514.     Point        delta, absdelta;
  1515.     Boolean        contained, vertTry;
  1516.     short        diamondSize, diagNum, tryNum, h, v, hh, vv;
  1517.  
  1518.     if (!(whichDevice = relatedWindow))
  1519.         whichDevice = window;
  1520.             /* If we have a window to stagger from, use the device for that window,
  1521.             ** else use the device for the window that is getting staggered. */
  1522.  
  1523.     deviceRect = GetWindowDeviceRectNMB(whichDevice);
  1524.         /* We now have the rect of the device we want to stagger within. */
  1525.  
  1526.     if (!EmptyRect(&gWindowPlacementRect))
  1527.         deviceRect = gWindowPlacementRect;
  1528.  
  1529.     contentRect = GetWindowContentRect(window);        /* Get where the window is now. */
  1530.     h = hh = contentRect.right  - contentRect.left;
  1531.     v = vv = contentRect.bottom - contentRect.top;
  1532.     if (sizeInfo.left)
  1533.         if (h < sizeInfo.left)
  1534.             h = sizeInfo.left;
  1535.     if (sizeInfo.right)
  1536.         if (h > sizeInfo.right)
  1537.             h = sizeInfo.right;
  1538.     if (sizeInfo.top)
  1539.         if (v < sizeInfo.top)
  1540.             v = sizeInfo.top;
  1541.     if (sizeInfo.bottom)
  1542.         if (v > sizeInfo.bottom)
  1543.             v = sizeInfo.bottom;
  1544.     contentRect.right  = contentRect.left + h;
  1545.     contentRect.bottom = contentRect.top  + v;
  1546.  
  1547.     oldWindowRect = GetWindowStructureRect(window);
  1548.  
  1549.     newWindowRect.top    = deviceRect.top  + kStartPtV;
  1550.     newWindowRect.left   = deviceRect.left + kStartPtH;
  1551.     newWindowRect.bottom = newWindowRect.top  + oldWindowRect.bottom - oldWindowRect.top;
  1552.     newWindowRect.right  = newWindowRect.left + oldWindowRect.right  - oldWindowRect.left;
  1553.     newWindowRect.right  += (h - hh);
  1554.     newWindowRect.bottom += (v - vv);
  1555.         /* We now have a new rect for the first window position slot. */
  1556.  
  1557.     slot1 = newWindowRect;
  1558.         /* We keep this slot in case we find no acceptable slots.  If we
  1559.         ** don't find an acceptable one, we will use this one anyway. */
  1560.  
  1561.     diamondSize = (kStaggerH < kStaggerV) ? kStaggerH : kStaggerV;
  1562.     for (diagNum = 0, vertTry = true;;) {
  1563.         for (tryNum = 0;; ++tryNum) {
  1564.  
  1565.             SectRect(&newWindowRect, &deviceRect, &testRct1);
  1566.             if (!(contained = EqualRect(&newWindowRect, &testRct1))) break;
  1567.                 /* Break if the slot we are testing went off the device. */
  1568.  
  1569.             for (staggerFromWindow = FrontWindow(); staggerFromWindow;
  1570.                  staggerFromWindow = (WindowPtr)((WindowPeek)staggerFromWindow)->nextWindow) {
  1571.                 if (!((WindowPeek)staggerFromWindow)->visible) continue;
  1572.                     /* This window is invisible.  Staggering from an invisible
  1573.                     ** window is going to confuse the user, so don't do it. */
  1574.  
  1575.                 testRct1 = GetWindowDeviceRect(staggerFromWindow);
  1576.                 testRct2 = GetRectDeviceRect(deviceRect);
  1577.                 if (!EqualRect(&testRct1, &testRct2)) continue;
  1578.                     /* This window doesn't belong to the device we are trying to
  1579.                     ** stagger on, so skip it and go to the next window. */
  1580.  
  1581.                 staggerFromRect = GetWindowStructureRect(staggerFromWindow);
  1582.                 delta.v = staggerFromRect.top  - newWindowRect.top;
  1583.                 delta.h = staggerFromRect.left - newWindowRect.left;
  1584.                 if ((absdelta.v = delta.v) < 0)
  1585.                     absdelta.v = -delta.v;
  1586.                 if ((absdelta.h = delta.h) < 0)
  1587.                     absdelta.h = -delta.h;
  1588.                 if ((absdelta.h + absdelta.v) < diamondSize) {
  1589.                     if ((delta.h + delta.v) > 0)
  1590.                         OffsetRect(&newWindowRect, delta.h, delta.v);
  1591.                             /* If the window that took our slot is closer to
  1592.                             ** the lower-right corner than we are, then use
  1593.                             ** this window's location as the basis for the
  1594.                             ** slots from now on.  This will align new windows
  1595.                             ** with previous windows that are not gridded to
  1596.                             ** the default slot positions.  The check for > 0
  1597.                             ** is necessary to prevent bouncing between two
  1598.                             ** existing windows.  This check guarantees that
  1599.                             ** we are progressing with the evaluation. */
  1600.                     break;
  1601.                         /* Break because this slot is already used. */
  1602.                 }
  1603.             }
  1604.  
  1605.             if (!staggerFromWindow) break;
  1606.                 /* If the window pointer is nil, then we tried all the windows
  1607.                 ** and none of them occupied this slot.  This means that the
  1608.                 ** slot is available for the new window. */
  1609.  
  1610.                 OffsetRect(&newWindowRect, kStaggerH, kStaggerV);
  1611.                 /* Since this slot was taken, try the next slot and go through
  1612.                 ** the window list again. */
  1613.         }
  1614.  
  1615.         if (contained) break;
  1616.         newWindowRect = slot1;
  1617.         if (!tryNum) {
  1618.             if (!vertTry) break;        /* Nothing works.  No spots at all. */
  1619.             vertTry = false;            /* Try across for the next pass. */
  1620.             diagNum = 0;
  1621.         }
  1622.         ++diagNum;
  1623.         if (vertTry)
  1624.             OffsetRect(&newWindowRect, 0, diagNum * kStaggerV);
  1625.         else
  1626.             OffsetRect(&newWindowRect, diagNum * kStaggerH, 0);
  1627.     }
  1628.  
  1629.     OffsetRect(&contentRect, newWindowRect.left - oldWindowRect.left,
  1630.                             newWindowRect.top  - oldWindowRect.top);
  1631.         /* Calculate the new content rect. */
  1632.  
  1633.     MoveWindow(window, contentRect.left, contentRect.top, false);
  1634.         /* Move the window to the new location. */
  1635.  
  1636.     oldWindowRect = newWindowRect;
  1637.  
  1638.     if (newWindowRect.right > (deviceRect.right - 2))
  1639.         newWindowRect.right = (deviceRect.right - 2);
  1640.  
  1641.     if (newWindowRect.bottom > (deviceRect.bottom - 2))
  1642.         newWindowRect.bottom = (deviceRect.bottom - 2);
  1643.  
  1644.     h = newWindowRect.right  - oldWindowRect.right;
  1645.     v = newWindowRect.bottom - oldWindowRect.bottom;
  1646.  
  1647.     SizeWindow(window, contentRect.right  - contentRect.left + h,
  1648.                        contentRect.bottom - contentRect.top + v, false);
  1649.         /* The window may have also changed size, due to sizeInfo or not fitting on the screen. */
  1650.  
  1651.  
  1652.     return(contentRect);
  1653. }
  1654.  
  1655.  
  1656.  
  1657. /*****************************************************************************/
  1658.  
  1659.  
  1660.  
  1661. void    StandardAbout(short appNameStringID)
  1662. {
  1663.     StringHandle    apNameHndl;
  1664.     VersRecHndl        curVersion;
  1665.     Str255            apName;
  1666.     Str255            verNum = "\p????";
  1667.     Ptr                verNumLocation;
  1668.     OSErr            err;
  1669.  
  1670.     apNameHndl = (StringHandle)nil;
  1671.     if (appNameStringID != kUseRealAppName) {
  1672.         if (appNameStringID != kUseCreatorString)
  1673.             apNameHndl = GetString(appNameStringID);
  1674.         if (!apNameHndl)
  1675.             apNameHndl = (StringHandle)GetAppResource(gSignature, 0, &err);
  1676.     }
  1677.  
  1678.     if ((!apNameHndl) || (appNameStringID == kUseRealAppName))
  1679.         pcpy(apName, gAppName);
  1680.     else
  1681.         pcpy(apName, *apNameHndl);
  1682.  
  1683.     curVersion = (VersRecHndl) GetAppResource('vers', 1, &err);
  1684.     if (curVersion) {
  1685.         verNumLocation = (Ptr)((long)(*curVersion)->shortVersion +
  1686.                          (long)*(*curVersion)->shortVersion + 1);
  1687.         pcpy(verNum, (StringPtr)verNumLocation);
  1688.     }
  1689.  
  1690.     ParamText(apName, verNum, "\p", "\p");
  1691.  
  1692.     CenteredAlert(rStdAboutAlert, nil, nil);
  1693. }
  1694.  
  1695.  
  1696.  
  1697. /*****************************************************************************/
  1698.  
  1699.  
  1700.  
  1701. void    StandardInitialization(short callsToMoreMasters)
  1702. {
  1703.     InitToolBox();
  1704.  
  1705.     while (callsToMoreMasters--) MoreMasters();
  1706.  
  1707.     PullApplicationToFront();
  1708.     GetSystemInfo();
  1709. }
  1710.  
  1711.  
  1712.  
  1713. /*****************************************************************************/
  1714.  
  1715.  
  1716.  
  1717. void    StandardMenuSetup(short mbarID, short appleMenuID)
  1718. {
  1719.     Handle    mbar;
  1720.     short    i, id;
  1721.  
  1722.     mbar = GetNewMBar(mbarID);                            /* Read menus into menu bar. */
  1723.     if (!mbar) return;                                    /* Maybe we're faceless, so we're done. */
  1724.  
  1725.     SetMenuBar(mbar);                                    /* Install menus. */
  1726.     DisposeHandle(mbar);
  1727.     AppendResMenu(GetMenuHandle(appleMenuID), 'DRVR');    /* Add DA names to Apple menu. */
  1728.  
  1729.     mbar = GetResource('MBAR', mbarID);
  1730.     for (i = **(short **)mbar; i; --i) {
  1731.         mbar = GetResource('MBAR', mbarID);        /* Make sure it's in memory for dereference. */
  1732.         id   = (*(short **)mbar)[i];
  1733.         InsertHierMenus(GetMenuHandle(id));
  1734.     }
  1735.  
  1736.     DrawMenuBar();
  1737. }
  1738.  
  1739.  
  1740.  
  1741. /*****************************************************************************/
  1742.  
  1743.  
  1744.  
  1745. void    InsertHierMenus(MenuHandle menu)
  1746. {
  1747.     short        item, cmd, mark;
  1748.     MenuHandle    hier;
  1749.  
  1750.     for (item = CountMItems(menu); item; --item) {
  1751.         GetItemCmd(menu, item, &cmd);
  1752.         if (cmd == 0x1B) {
  1753.             GetItemMark(menu, item, &mark);
  1754.             hier = GetMenu(mark);
  1755.             if (hier) {
  1756.                 InsertMenu(hier, -1);
  1757.                 InsertHierMenus(hier);
  1758.             }
  1759.         }
  1760.     }
  1761. }
  1762.  
  1763.  
  1764.  
  1765. /*****************************************************************************/
  1766.  
  1767.  
  1768.  
  1769. /* Check to see if a given trap is implemented. */
  1770.  
  1771. Boolean TrapExists(short theTrap)
  1772. {
  1773.     TrapType    theTrapType;
  1774.  
  1775.     theTrapType = GetTrapType(theTrap);
  1776.     if ((theTrapType == ToolTrap) && ((theTrap &= 0x07FF) >= NumToolboxTraps()))
  1777.         theTrap = _Unimplemented;
  1778.  
  1779.     return(NGetTrapAddress(_Unimplemented, ToolTrap) != NGetTrapAddress(theTrap, theTrapType));
  1780. }
  1781.  
  1782.  
  1783.  
  1784. /*****************************************************************************/
  1785.  
  1786.  
  1787.  
  1788. /* Zoom the window to the size appropriate for the device that contains the
  1789. ** most of the window.  An additional feature is that you can state the
  1790. ** maximum that a window should be zoomed, either horizontally or vertically.
  1791. ** If you pass in a maximum of 0 for the zoom for either direction, then that
  1792. ** direction will be zoomed to fit the device. */
  1793.  
  1794. void    ZoomToWindowDevice(WindowPtr window, short maxWidth, short maxHeight,
  1795.                            short zoomDir, Boolean front)
  1796. {
  1797.      GrafPtr    oldPort;
  1798.     Rect    contentRect, structureRect, deviceRect, newRect;
  1799.     short    width, height, dx, dy;
  1800.  
  1801.     GetPort(&oldPort);
  1802.     SetPort(window);
  1803.     EraseRect(&window->portRect);         /* Recommended for cosmetic reasons. */
  1804.  
  1805.     /* If there is the possibility of multiple gDevices, then we must check them to
  1806.     ** make sure we are zooming onto the right display device when zooming out. */
  1807.  
  1808.     if (zoomDir == inZoomOut) {
  1809.  
  1810.         contentRect      = GetWindowContentRect(window);
  1811.         structureRect = GetWindowStructureRect(window);
  1812.         deviceRect      = GetWindowDeviceRectNMB(window);
  1813.  
  1814.         deviceRect.left   += (contentRect.left - structureRect.left + 2);
  1815.         deviceRect.top    += (contentRect.top - structureRect.top + 2);
  1816.         deviceRect.right  -= (structureRect.right - contentRect.right + 1);
  1817.         deviceRect.bottom -= (structureRect.bottom - contentRect.bottom + 1);
  1818.         newRect = deviceRect;
  1819.  
  1820.         if (maxWidth)
  1821.             if ((width = deviceRect.right - deviceRect.left) > maxWidth)
  1822.                 newRect.right = (newRect.left = contentRect.left) + maxWidth;
  1823.         if (maxHeight)
  1824.             if ((height = deviceRect.bottom - deviceRect.top) > maxHeight)
  1825.                 newRect.bottom = (newRect.top = contentRect.top) + maxHeight;
  1826.         if ((dx = deviceRect.left - newRect.left) < 0)
  1827.             if ((dx = deviceRect.right - newRect.right) > 0)
  1828.                 dx = 0;
  1829.         if ((dy = deviceRect.top - newRect.top) < 0)
  1830.             if ((dy = deviceRect.bottom - newRect.bottom) > 0)
  1831.                 dy = 0;
  1832.         OffsetRect(&newRect, dx, dy);
  1833.  
  1834.         (*(WStateDataHandle)(((WindowPeek)window)->dataHandle))->stdState = newRect;
  1835.             /* Set up the WStateData record for this window. */
  1836.     }
  1837.  
  1838.     ZoomWindow(window, zoomDir, front);
  1839.     SetPort(oldPort);
  1840. }
  1841.  
  1842.  
  1843.  
  1844. /*****************************************************************************/
  1845. /*****************************************************************************/
  1846. /*****************************************************************************/
  1847.  
  1848.  
  1849.  
  1850. void    DoDrawGrowIcon(WindowPtr window, Boolean horLine, Boolean verLine)
  1851. {
  1852.     WindowPtr    oldPort;
  1853.     Rect        rct;
  1854.     RgnHandle    oldClip, newClip;
  1855.  
  1856.     GetPort(&oldPort);
  1857.     SetPort(window);
  1858.  
  1859.     rct = window->portRect;
  1860.     rct.left = rct.right  - 15;
  1861.     rct.top  = rct.bottom - 15;
  1862.  
  1863.     if (!((WindowPeek)window)->hilited) {
  1864.         FrameRect(&rct);
  1865.         ++rct.top;
  1866.         ++rct.left;
  1867.         EraseRect(&rct);
  1868.         SetPort(oldPort);
  1869.         return;
  1870.     }
  1871.  
  1872.     oldClip = NewRgn();
  1873.     newClip = NewRgn();
  1874.  
  1875.     if (horLine)
  1876.         rct.left = window->portRect.left;
  1877.     if (verLine)
  1878.         rct.top  = window->portRect.top;
  1879.     RectRgn(newClip, &rct);
  1880.  
  1881.     GetClip(oldClip);
  1882.     SetClip(newClip);
  1883.     DrawGrowIcon(window);        /* Draw grow icon without scrollbar lines. */
  1884.  
  1885.     SetClip(oldClip);
  1886.     DisposeRgn(oldClip);
  1887.     DisposeRgn(newClip);
  1888.  
  1889.     SetPort(oldPort);
  1890. }
  1891.  
  1892.  
  1893.  
  1894. /*****************************************************************************/
  1895.  
  1896.  
  1897.  
  1898. /* This is used to "intelligently" insert a menu item into a menu.  Pass it
  1899. ** the menu to be modified, the text of the item being added, plus where the
  1900. ** item is to be inserted.  The location to be inserted is described by two
  1901. ** parameters:  section & where.
  1902. **
  1903. ** section:  Indicates which group of menu items you wish to add an item to.
  1904. **           Menu item section 1 is all of the items before the first
  1905. **           dividing line.  Menu item section 2 is all items after the
  1906. **           first dividing line and before the second, and so on.  If you
  1907. **           have no dividing lines, you have just 1 section so pass in 1.
  1908. **
  1909. ** where:    Indicates the item position relative to the section.  To add an
  1910. **           item such that it is the first item in a section, pass in a 1.
  1911. **           It will be added in front of the first item in the section.
  1912. **
  1913. **           NOTE:  You should never pass in a section or where parameter of 0.
  1914. **
  1915. ** Negative values for "where" are magic.  If where = kMenuItemTxtInsert, then
  1916. ** it inserts the item alphabetically into the section.  A where of
  1917. ** kMenuItemNumInsert works the same as kMenuItemTxtInsert, except it treats
  1918. ** the strings are numbers for comparison purposes.  If you want to add the
  1919. ** item to the end of a section, use kMenuItemSectionEnd.
  1920. **
  1921. ** As a final goodie, SmartInsMenuItem returns the menu item # from the
  1922. ** beginning of the menu, not section.
  1923. */
  1924.  
  1925. short    SmartInsMenuItem(MenuHandle theMenu, StringPtr theText, short section, short where)
  1926. {
  1927.     short    numItems, base, i;
  1928.     short    insertType, val;
  1929.     Str255    cmpTxt, txt;
  1930.  
  1931.     numItems = CountMItems(theMenu);    /* Total number of items in menu. */
  1932.  
  1933.     if (--section < 0)
  1934.         section = 0;                    /* We want section 0-based. */
  1935.  
  1936.     for (base = 0, i = 1; (section) && (i <= numItems); ++i) {
  1937.         GetMenuItemText(theMenu, base + i, txt);
  1938.         if (txt[1] == '-') {
  1939.             base = i;
  1940.             --section;
  1941.         }
  1942.     }        /* base now tells us our section starting offset. */
  1943.  
  1944.     if (where < 0) {        /* If magic mode... */
  1945.  
  1946.         InsertMenuItem(theMenu, theText, 0);            /* Take out meta characters */
  1947.         GetMenuItemText(theMenu, 1, cmpTxt);            /* for comparison purposes. */
  1948.         DeleteMenuItem(theMenu, 1);
  1949.  
  1950.         insertType = where;
  1951.         val = p2num(cmpTxt, 10, nil);
  1952.  
  1953.         for (where = 1; i <= (numItems - base); ++where) {
  1954.             GetMenuItemText(theMenu, where + base, txt);
  1955.             if (txt[1] == '-') break;
  1956.             if ((insertType == kMenuItemTxtInsert) && ((IUCompString(cmpTxt, txt) < 0))) break;
  1957.             if ((insertType == kMenuItemNumInsert) && (val < p2num(txt, 10, nil)))       break;
  1958.         }
  1959.     }
  1960.  
  1961.     where += base;
  1962.     InsertMenuItem(theMenu, theText, where - 1);        /* InsMenuItem does an insert-after. */
  1963.  
  1964.     return(where);
  1965. }
  1966.  
  1967.  
  1968.  
  1969. /*****************************************************************************/
  1970.  
  1971.  
  1972.  
  1973. short    CountMSections(MenuHandle theMenu)
  1974. {
  1975.     short    numItems, numSections, i;
  1976.     Str255    txt;
  1977.  
  1978.     numItems = CountMItems(theMenu);    /* Total number of items in menu. */
  1979.  
  1980.     for (numSections = i = 1; i <= numItems; ++i) {
  1981.         GetMenuItemText(theMenu, i, txt);
  1982.         if (txt[1] == '-')
  1983.             ++numSections;
  1984.     }
  1985.  
  1986.     return(numSections);
  1987. }
  1988.  
  1989.  
  1990.  
  1991. /*****************************************************************************/
  1992.  
  1993.  
  1994.  
  1995. short    FindMenuItem(MenuHandle theMenu, StringPtr cmpTxt)
  1996. {
  1997.     short    item;
  1998.     Str255    txt;
  1999.  
  2000.     for (item = CountMItems(theMenu); item; --item) {
  2001.         GetMenuItemText(theMenu, item, txt);
  2002.         if (!IUCompString(cmpTxt, txt)) break;
  2003.     }
  2004.  
  2005.     return(item);
  2006. }
  2007.  
  2008.  
  2009.  
  2010. /*****************************************************************************/
  2011.  
  2012.  
  2013.  
  2014. OSErr    PersistFSSpec(PFSSpecPtr pfss)
  2015. {
  2016.     OSErr            err;
  2017.     HParamBlockRec    pb;
  2018.     char            delim;
  2019.  
  2020.     SetMem(&pb, 0, sizeof(HParamBlockRec));        /* Make us a happy ParamBlock. */
  2021.     pb.volumeParam.ioNamePtr = pfss->volName;
  2022.  
  2023.     if (!(pfss->fss.name[0])) {                /* If no file name, then there's no file. */
  2024.         pfss->volName[0] = 0;                /* Zap all remnants of file specification. */
  2025.         pfss->fss.vRefNum = 0;
  2026.         return(noErr);
  2027.     }
  2028.  
  2029.     pb.volumeParam.ioVRefNum = pfss->fss.vRefNum;
  2030.     if (pb.volumeParam.ioVRefNum) {
  2031.         pfss->volName[0] = 0;    /* If we are passed in a vRefNum, then we are
  2032.                                 ** wanting the volume name.  This is what we are
  2033.                                 ** looking to get, so show it as currently missing. */
  2034.         err = PBHGetVInfo(&pb, false);
  2035.     }
  2036.     else {
  2037.         if (!(pfss->volName[0])) return(noErr);
  2038.  
  2039.         pb.volumeParam.ioVolIndex = -1;        /* Use the name to find the vRefNum. */
  2040.         delim = (gAUXVersion) ? '/' : ':';
  2041.         if (pfss->volName[pfss->volName[0]] != delim)
  2042.             pfss->volName[++(pfss->volName[0])] = delim;
  2043.                 /* Make sure that volume name ends with a delimiter. */
  2044.  
  2045.         if (!(err = PBHGetVInfo(&pb, false)))
  2046.             pfss->fss.vRefNum = pb.volumeParam.ioVRefNum;
  2047.     }
  2048.  
  2049.     return(err);
  2050. }
  2051.  
  2052.  
  2053.  
  2054. /*****************************************************************************/
  2055.  
  2056.  
  2057.  
  2058. StringPtr    PathNameFromDirID(long dirID, short vRefNum, StringPtr str)
  2059. {
  2060.     CInfoPBRec    block;
  2061.     Str255        directoryName;
  2062.  
  2063.     *str = 0;
  2064.     block.dirInfo.ioNamePtr = directoryName;
  2065.     block.dirInfo.ioDrParID = dirID;
  2066.  
  2067.     do {
  2068.         block.dirInfo.ioVRefNum   = vRefNum;
  2069.         block.dirInfo.ioFDirIndex = -1;
  2070.         block.dirInfo.ioDrDirID   = block.dirInfo.ioDrParID;
  2071.  
  2072.         if (PBGetCatInfo(&block, false)) {
  2073.             *str = 0;
  2074.             break;
  2075.         }
  2076.  
  2077.         if (gAUXVersion) {
  2078.             if (directoryName[1] != '/')
  2079.                 pcat(directoryName, "\p/");
  2080.                     /* If this isn't root (i.e. '/'), append a slash ('/'). */
  2081.         } else pcat(directoryName, "\p:");
  2082.             /* Append a Macintosh style colon (':'). */
  2083.  
  2084.         pcat(directoryName, str);
  2085.         pcpy(str, directoryName);
  2086.  
  2087.     } while (block.dirInfo.ioDrDirID != fsRtDirID);
  2088.  
  2089.     return(str);
  2090. }
  2091.  
  2092.  
  2093.  
  2094. /*****************************************************************************/
  2095.  
  2096.  
  2097.  
  2098. void    InitQuickTime(void)
  2099. {
  2100.     ComponentDescription    controllerDescriptor;
  2101. #ifdef powerc
  2102.     long                    qtFeatures;
  2103. #endif
  2104.  
  2105.     if (!gQTVersion) {
  2106.         if (!(Gestalt(gestaltQuickTime, &gQTVersion))) {
  2107. #ifdef powerc
  2108.             if ((!(Gestalt (gestaltQuickTimeFeatures, &qtFeatures)) &&
  2109.                 (qtFeatures & (1 << gestaltPPCQuickTimeLibPresent))))
  2110. #endif
  2111.                 if (EnterMovies())
  2112.                     gQTVersion = 0;
  2113.                 else {
  2114.                     controllerDescriptor.componentType         = 'play';
  2115.                     controllerDescriptor.componentSubType      = 0;
  2116.                     controllerDescriptor.componentManufacturer = 0;
  2117.                     controllerDescriptor.componentFlags        = 0;
  2118.                     controllerDescriptor.componentFlagsMask    = 0;
  2119.                     gMovieControllerComponent = FindNextComponent((Component)0, &controllerDescriptor);
  2120.             }
  2121.         }
  2122.     }
  2123. }
  2124.  
  2125.  
  2126.  
  2127. /*****************************************************************************/
  2128.  
  2129.  
  2130.  
  2131. RgnHandle    LocalScreenDepthRegion(short depth)
  2132. {
  2133.     RgnHandle    retRgn;
  2134.     GrafPtr        oldPort;
  2135.     Point        pt;
  2136.  
  2137.     retRgn = ScreenDepthRegion(depth);
  2138.     if (gScreenPort) {
  2139.         GetPort(&oldPort);
  2140.         SetPort(gScreenPort);
  2141.     }
  2142.  
  2143.     pt.h = pt.v = 0;
  2144.     GlobalToLocal(&pt);
  2145.     OffsetRgn(retRgn, pt.h, pt.v);
  2146.  
  2147.     if (gScreenPort) SetPort(oldPort);
  2148.     return(retRgn);
  2149. }
  2150.  
  2151.  
  2152.  
  2153. /*****************************************************************************/
  2154. /*****************************************************************************/
  2155. /*****************************************************************************/
  2156.  
  2157.  
  2158.  
  2159. pascal Boolean    AlertFilter(DialogPtr dlg, EventRecord *event, short *item)
  2160. {
  2161.     short    what, theChr, theMod, handled;
  2162.  
  2163.     what = event->what;
  2164.     if (event->what == keyDown) {
  2165.         theChr = event->message   & charCodeMask;
  2166.         theMod = event->modifiers & keyCodeMask;
  2167.         if ((theChr != 0x0D) && (theChr != 0x03))
  2168.             event->what = nullEvent;
  2169.         if (theMod & (cmdKey + optionKey + controlKey))
  2170.             event->what = nullEvent;
  2171.     }
  2172.     handled = KeyEquivFilter(dlg, event, item);
  2173.     event->what = what;
  2174.     return(handled);
  2175. }
  2176.  
  2177.  
  2178.  
  2179. /*****************************************************************************/
  2180.  
  2181.  
  2182.  
  2183. /* This code expects the key equivalents to be in item #2, which is a StatText
  2184. ** item that is located so the text is outside of the dialog.  This allows us
  2185. ** to put key equivalent information in the resource fork, so the key
  2186. ** equivalents are localizable.
  2187. **
  2188. ** An example save changes before closing or quitting res source with
  2189. ** keyEquiv info would look like:
  2190. **
  2191. ** resource 'DITL' (rYesNoCancel, purgeable) {
  2192. **     {
  2193. **         {71, 315, 91, 367}, Button     { enabled, "Save" },
  2194. **         {0, -1000, 20, 2},  StaticText { disabled,
  2195. **             "=S190001,=s190001,=D190003,=d190003,=.190104,1B190004" },
  2196. **         {71, 80, 91, 162},  Button { enabled, "Don’t Save" },
  2197. **         {71, 244, 91, 302}, Button { enabled, "Cancel" },
  2198. **         {11, 78, 61, 366},  StaticText { disabled,
  2199. **             "Save changes to the document “^0” before ^1?" },
  2200. **         {11, 23, 43, 55},        Icon { disabled, 2 }
  2201. **     }
  2202. ** };
  2203. **
  2204. ** The document name would be the string for param #0.
  2205. ** The text "closing" or "quitting" would be the string for param #1.
  2206. **
  2207. ** The keyEquiv entry is item #2, which has a rect that pushes it out of the
  2208. ** dialog.  The string info is interpreted as to what the key/modifier combo
  2209. ** is, and what dialog item it relates to.
  2210. **
  2211. ** A single key equiv entry is 8 characters.  Entries are separated by commas.
  2212. **
  2213. ** If the first character of an entry is an =, then the next character is the
  2214. ** key.  If the first character isn't an =, then the first two characters are
  2215. ** the hex value of the key.  (Ex:  =S or =s for save, 1B for ESC.)
  2216. **
  2217. ** If the key pressed is the same as the key value for any of the entries, then
  2218. ** the next two characters are the hex value for which modifiers to test.  This
  2219. ** modifier test value is anded with the modifier.  The result is then compared
  2220. ** to the value of the next two hex digits.  If they are equal, then the
  2221. ** modifiers are correct, as well as the key.  If this is so, we have a winner.
  2222. **
  2223. ** "=S190001,=s190001,=D190003,=d190003,=.190104,1B190004"
  2224. **
  2225. ** The above string breaks down as follows:
  2226. ** =S190001  =S  if event keypress is an S, check the modifier values
  2227. **           19  check controlKey/optionKey/cmdKey
  2228. **           00  all modifiers we are testing for should be false
  2229. **           01  if above is true, keypress maps to item # 1
  2230. ** =s190001  Same as =S, but lowercase
  2231. ** =D190001  Same as =S, but maps to item #3
  2232. ** =d190001  Same as =D, but lowercase
  2233. ** =.190104  =.  if event keypress is a period, check the modifier values
  2234. **           19  check controlKey/optionKey/cmdKey
  2235. **           01  controlKey/optionKey should be false, cmdKey should be true
  2236. **           04  if above is true, keypress maps to item # 4
  2237. ** 1B190004  1B  if event keypress is an ESC, check the modifier values
  2238. **           19  check controlKey/optionKey/cmdKey
  2239. **           00  all modifiers we are testing for should be false
  2240. **           04  if above is true, keypress maps to item # 4
  2241. */
  2242.  
  2243. pascal Boolean    KeyEquivFilter(DialogPtr dlg, EventRecord *event, short *item)
  2244. {
  2245.     short    itemType;
  2246.     Handle    itemHndl;
  2247.     Rect    itemRect;
  2248.     Str255    itemText;
  2249.     short    i, theChr, cc, theMod, equivChr, modMask, modVal, itemNum;
  2250.  
  2251.     if (event->what == updateEvt) {
  2252.         if (dlg == (DialogPtr)event->message)
  2253.             OutlineDialogItem(dlg, 1);
  2254.         return(false);
  2255.     }
  2256.  
  2257.     if (event->what != keyDown) return(false);
  2258.  
  2259.     itemNum = 0;
  2260.  
  2261.     theChr = event->message   & charCodeMask;
  2262.     theMod = event->modifiers & keyCodeMask;
  2263.  
  2264.     if ((theChr == 0x0D) || (theChr == 0x03)) {        /* If return or enter... */
  2265.         if (!(theMod & (cmdKey + optionKey + controlKey))) {
  2266.             *item = 1;
  2267.             return(true);
  2268.         }
  2269.     }
  2270.  
  2271.     GetDialogItem(dlg, 2, &itemType, &itemHndl, &itemRect);
  2272.     if (itemHndl) {
  2273.         GetDialogItemText(itemHndl, itemText);
  2274.         for (i = 1; i <= *itemText; i += 9) {
  2275.             cc = theChr;
  2276.             if (itemText[i] == (unsigned char)'≈')
  2277.                 if ((cc >= 'a') && (cc <= 'z')) cc -= 32;
  2278.             equivChr = GetHexByte((char *)(itemText + i));
  2279.             modMask  = GetHexByte((char *)(itemText + i + 2)) << 8;
  2280.             modVal   = GetHexByte((char *)(itemText + i + 4)) << 8;
  2281.             itemNum  = GetHexByte((char *)(itemText + i + 6));
  2282.             if (cc == equivChr)
  2283.                 if ((theMod & modMask) == modVal) break;
  2284.             itemNum = 0;
  2285.         }
  2286.     }
  2287.  
  2288.     if (itemNum) {
  2289.         GetDialogItem(dlg, itemNum, &itemType, &itemHndl, &itemRect);
  2290.         SelectButton((ControlHandle)itemHndl);
  2291.         *item = itemNum;
  2292.         return(true);
  2293.     }
  2294.  
  2295.     return(false);
  2296. }
  2297.  
  2298.  
  2299.  
  2300. /*****************************************************************************/
  2301. /*****************************************************************************/
  2302. /*****************************************************************************/
  2303.  
  2304.  
  2305.  
  2306. /* This function returns which kind of button the control is.  This does more
  2307. ** than GetCVariant in that it makes sure that the control is actually a
  2308. ** button.  It does this by comparing the defProc against the known defProc
  2309. ** for the various button types.  For 7.0, there is only one defProc for all
  2310. ** variants, but for pre-7.0, there is one defProc value for each variant.
  2311. ** The method below handles either case. */
  2312.  
  2313. short    GetButtonVariant(ControlHandle ctl)
  2314. {
  2315.     short            i;
  2316.     Boolean            stop;
  2317.     Rect            dummy;
  2318.     ControlHandle    dummyCtl;
  2319.  
  2320.     if (ctl) {
  2321.  
  2322.         if (gGetButtonVariant) {
  2323.             stop = false;
  2324.             i = (*gGetButtonVariant)(ctl, &stop);
  2325.             if (i >= 0) return(i);
  2326.             if (stop)   return(-1);
  2327.         }
  2328.  
  2329.         for (i = pushButProc; i <= radioButProc + useWFont; ++i) {
  2330.             if (i == radioButProc + 1)
  2331.                 i = pushButProc + useWFont;
  2332.             if (!gButtonProcs[i]) {
  2333.                 SetRect(&dummy, 0, 0, 0, 0);
  2334.                 dummyCtl = NewControl((*ctl)->contrlOwner, &dummy, (ConstStr255Param)"\p",
  2335.                                       false, 1, 0, 1, i, 0L);
  2336.                 if (dummyCtl) {
  2337.                     gButtonProcs[i] = (*dummyCtl)->contrlDefProc;
  2338.                     DisposeControl(dummyCtl);
  2339.                 }
  2340.             }
  2341.             if (StripAddress((*ctl)->contrlDefProc) == StripAddress(gButtonProcs[i]))
  2342.                 return(GetControlVariant(ctl) & (0xFFFF - useWFont));
  2343.                     /* The handle may be locked, which means that the hi-bit
  2344.                     ** may be on, thus invalidating the compare.  Dereference the
  2345.                     ** handles to get rid of this possibility. */
  2346.         }
  2347.     }
  2348.  
  2349.     return(-1);
  2350. }
  2351.  
  2352.  
  2353.  
  2354. /*****************************************************************************/
  2355.  
  2356.  
  2357.  
  2358. Boolean GetCheckOrRadio(DialogPtr dlgPtr, short itemNo)
  2359. {
  2360.     short    iKind;
  2361.     Handle    iHandle;
  2362.     Rect    iRect;
  2363.  
  2364.     GetDialogItem(dlgPtr, itemNo, &iKind, &iHandle, &iRect);
  2365.     return(GetControlValue((ControlHandle)iHandle) != 0);
  2366. }
  2367.  
  2368.  
  2369.  
  2370. /*****************************************************************************/
  2371.  
  2372.  
  2373.  
  2374. Boolean    IsScrollBar(ControlHandle ctl)
  2375. {
  2376.     Rect            dummy;
  2377.     ControlHandle    dummyCtl;
  2378.  
  2379.     if (!ctl) return(false);
  2380.  
  2381.     if (!gScrollProc) {
  2382.         SetRect(&dummy, 0, 0, 16, 100);
  2383.         dummyCtl = NewControl((*ctl)->contrlOwner, &dummy, (ConstStr255Param)"\p",
  2384.                               false, 1, 0, 1, scrollBarProc, 0L);
  2385.         if (dummyCtl) {
  2386.             gScrollProc = (*dummyCtl)->contrlDefProc;
  2387.             DisposeControl(dummyCtl);
  2388.         }
  2389.     }
  2390.  
  2391.     return(StripAddress((*ctl)->contrlDefProc) == StripAddress(gScrollProc));
  2392.         /* The handle may be locked, which means that the hi-bit
  2393.         ** may be on, thus invalidating the compare.  Dereference the
  2394.         ** handles to get rid of this possibility. */
  2395. }
  2396.  
  2397.  
  2398.  
  2399. /*****************************************************************************/
  2400.  
  2401.  
  2402.  
  2403. void    MoveStyledControl(ControlHandle ctl, short xloc, short yloc)
  2404. {
  2405.     char    vv, hh;
  2406.  
  2407.     if (GetControlValue(ctl) == 1) {
  2408.         if (GetButtonVariant(ctl) == pushButProc) {
  2409.             hh = (*ctl)->contrlHilite;
  2410.             (*ctl)->contrlHilite = 1;        /* Force outline off. */
  2411.             OutlineControl(ctl);
  2412.             (*ctl)->contrlHilite = hh;
  2413.         }
  2414.     }
  2415.  
  2416.     vv = (*ctl)->contrlVis;
  2417.     HideStyledControl(ctl);
  2418.     MoveControl(ctl, xloc, yloc);
  2419.     (*ctl)->contrlVis = vv;
  2420.  
  2421.     DoDraw1Control(ctl, false);
  2422. }
  2423.  
  2424.  
  2425.  
  2426. /*****************************************************************************/
  2427.  
  2428.  
  2429.  
  2430. void    SizeStyledControl(ControlHandle ctl, short xsize, short ysize)
  2431. {
  2432.     char    vv, hh;
  2433.  
  2434.     if (GetControlValue(ctl) == 1) {
  2435.         if (GetButtonVariant(ctl) == pushButProc) {
  2436.             hh = (*ctl)->contrlHilite;
  2437.             (*ctl)->contrlHilite = 1;        /* Force outline off. */
  2438.             OutlineControl(ctl);
  2439.             (*ctl)->contrlHilite = hh;
  2440.         }
  2441.     }
  2442.  
  2443.     vv = (*ctl)->contrlVis;
  2444.     HideStyledControl(ctl);
  2445.     SizeControl(ctl, xsize, ysize);
  2446.     (*ctl)->contrlVis = vv;
  2447.  
  2448.     DoDraw1Control(ctl, false);
  2449. }
  2450.  
  2451.  
  2452.  
  2453. /*****************************************************************************/
  2454.  
  2455.  
  2456.  
  2457. void    SetStyledCtlValue(ControlHandle ctl, short value)
  2458. {
  2459.     char    hh;
  2460.  
  2461.     if (value < (*ctl)->contrlMin) value = (*ctl)->contrlMin;    /* Don't let it draw on its own. */
  2462.     if (value > (*ctl)->contrlMax) value = (*ctl)->contrlMax;
  2463.     if ((*ctl)->contrlValue != value) {
  2464.         (*ctl)->contrlValue  = value;
  2465.         DoDraw1Control(ctl, false);        /* This routine does the right thing for popups. */
  2466.     }
  2467.  
  2468.     if (GetButtonVariant(ctl) == pushButProc) {
  2469.         if (!value) {
  2470.             hh = (*ctl)->contrlHilite;
  2471.             (*ctl)->contrlHilite = 1;        /* Force outline off. */
  2472.             OutlineControl(ctl);
  2473.             (*ctl)->contrlHilite = hh;
  2474.         }
  2475.         else
  2476.             OutlineControl(ctl);
  2477.     }
  2478. }
  2479.  
  2480.  
  2481.  
  2482. /*****************************************************************************/
  2483.  
  2484.  
  2485.  
  2486. void    ShowStyledControl(ControlHandle ctl)
  2487. {
  2488.     Boolean        didPopup;
  2489.     WindowPtr    oldPort, window;
  2490.     RgnHandle    oldClip, newClip;
  2491.     Point        org;
  2492.     Rect        srct;
  2493.  
  2494.     if (!(*ctl)->contrlVis) {
  2495.  
  2496.         didPopup = false;
  2497.         if (gPopupProc) {        /* The popup control does not handle negative coords. */
  2498.             if (StripAddress((*ctl)->contrlDefProc) == StripAddress(gPopupProc)) {
  2499.                 didPopup = true;
  2500.                 GetPort(&oldPort);
  2501.                 SetPort(window = (*ctl)->contrlOwner);
  2502.                 GetClip(oldClip = NewRgn());    /* We draw it once, so that internals   */
  2503.                 SetRect(&srct, 0, 0, 0, 0);        /* are fixed up.  We don't want to show */
  2504.                 ClipRect(&srct);                /* a flash though. */
  2505.  
  2506.                 RectRgn(newClip = NewRgn(), &(window->portRect));
  2507.                 org.h = window->portRect.left;
  2508.                 org.v = window->portRect.top;
  2509.                 SetOrigin(0, 0);
  2510.  
  2511.                 UseControlStyle(ctl);
  2512.                 OffsetRect(&((*ctl)->contrlRect), -org.h, -org.v);    /* Completely clipped out. */
  2513.                 ShowControl(ctl);                                    /* Just to fix internals.  */
  2514.                 Draw1Control(ctl);
  2515.  
  2516.                 SectRgn(newClip, oldClip, newClip);
  2517.                 OffsetRgn(newClip, -org.h, -org.v);
  2518.                 SetClip(newClip);
  2519.                 Draw1Control(ctl);                /* Now really show it. */
  2520.                 UseControlStyle(nil);
  2521.  
  2522.                 OffsetRect(&((*ctl)->contrlRect), org.h, org.v);
  2523.                 SetOrigin(org.h, org.v);
  2524.                 SetClip(oldClip);
  2525.                 DisposeRgn(newClip);
  2526.                 DisposeRgn(oldClip);
  2527.  
  2528.                 SetPort(oldPort);
  2529.             }
  2530.         }
  2531.  
  2532.         if (!didPopup) {
  2533.             (*ctl)->contrlVis = 255;
  2534.             DoDraw1Control(ctl, false);
  2535.         }
  2536.     }
  2537. }
  2538.  
  2539.  
  2540.  
  2541. /*****************************************************************************/
  2542.  
  2543.  
  2544.  
  2545. void    HideStyledControl(ControlHandle ctl)
  2546. {
  2547.     char        hh;
  2548.     Boolean        didPopup;
  2549.     WindowPtr    oldPort, window;
  2550.     RgnHandle    oldClip, newClip;
  2551.     Point        org;
  2552.     Rect        srct;
  2553.  
  2554.     if (!(*ctl)->contrlVis) return;
  2555.  
  2556.     if (GetButtonVariant(ctl) == pushButProc) {
  2557.         if (GetControlValue(ctl) == 1) {
  2558.             hh = (*ctl)->contrlHilite;
  2559.             (*ctl)->contrlHilite = 1;        /* Force outline off. */
  2560.             OutlineControl(ctl);
  2561.             (*ctl)->contrlHilite = hh;
  2562.             if ((*ctl)->contrlVis) {
  2563.                 GetPort(&oldPort);
  2564.                 SetPort(window = (*ctl)->contrlOwner);
  2565.                 srct = (*ctl)->contrlRect;
  2566.                 InsetRect(&srct, kButtonFrameInset, kButtonFrameInset);
  2567.                 InvalRect(&srct);
  2568.                 SetPort(oldPort);
  2569.             }
  2570.         }
  2571.     }
  2572.  
  2573.     didPopup = false;
  2574.     if (gPopupProc) {        /* The popup control does not handle negative coords. */
  2575.         if (StripAddress((*ctl)->contrlDefProc) == StripAddress(gPopupProc)) {
  2576.             didPopup = true;
  2577.             GetPort(&oldPort);
  2578.             SetPort(window = (*ctl)->contrlOwner);
  2579.             GetClip(oldClip = NewRgn());    /* We draw it once, so that internals   */
  2580.             SetRect(&srct, 0, 0, 0, 0);        /* are fixed up.  We don't want to show */
  2581.             ClipRect(&srct);                /* a flash though. */
  2582.  
  2583.             RectRgn(newClip = NewRgn(), &(window->portRect));
  2584.             org.h = window->portRect.left;
  2585.             org.v = window->portRect.top;
  2586.             SetOrigin(0, 0);
  2587.  
  2588.             OffsetRect(&((*ctl)->contrlRect), -org.h, -org.v);    /* Completely clipped out. */
  2589.             Draw1Control(ctl);                                    /* Just to fix internals.  */
  2590.  
  2591.             SectRgn(newClip, oldClip, newClip);
  2592.             OffsetRgn(newClip, -org.h, -org.v);
  2593.             SetClip(newClip);
  2594.             HideControl(ctl);                /* Now really hide it. */
  2595.  
  2596.             OffsetRect(&((*ctl)->contrlRect), org.h, org.v);
  2597.             SetOrigin(org.h, org.v);
  2598.             SetClip(oldClip);
  2599.             DisposeRgn(newClip);
  2600.             DisposeRgn(oldClip);
  2601.  
  2602.             SetPort(oldPort);
  2603.         }
  2604.     }
  2605.  
  2606.     if (!didPopup) HideControl(ctl);
  2607. }
  2608.  
  2609.  
  2610.  
  2611. /*****************************************************************************/
  2612.  
  2613.  
  2614.  
  2615. void    OffsetControl(ControlHandle ctl, short dx, short dy)
  2616. {
  2617.     Rect    ctlRect;
  2618.  
  2619.     ctlRect = (*ctl)->contrlRect;
  2620.     MoveStyledControl(ctl, ctlRect.left + dx, ctlRect.top + dy);
  2621. }
  2622.  
  2623.  
  2624.  
  2625. /*****************************************************************************/
  2626.  
  2627.  
  2628.  
  2629. /* Given any control handle, this will draw an outline around it.  This is used
  2630. ** for the default button of a window.  The extra nice feature here is that
  2631. ** I’ll erase the outline for buttons that are inactive.  Seems like there
  2632. ** should be a Toolbox call for getting a control’s hilite state.  Since there
  2633. ** isn’t, I have to look into the control record myself.  This should be called
  2634. ** for update and activate events.
  2635. **
  2636. ** The method for determining the oval diameters for the roundrect is a little
  2637. ** different than that recommended by Inside Mac. IM I-407 suggests that you
  2638. ** use a hardcoded (16,16) for the diameters.  However, this only looks good
  2639. ** for small roundrects.  For larger ones, the outline doesn’t follow the inner
  2640. ** roundrect because the CDEF for simple buttons doesn’t use (16,16).  Instead,
  2641. ** it uses half the height of the button as the diameter.  By using this
  2642. ** formula, too, our outlines look better. */
  2643.  
  2644. void    OutlineControl(ControlHandle button)
  2645. {
  2646.     WindowPtr    oldPort;
  2647.     Rect        theRect;
  2648.     PenState    curPen;
  2649.     short        buttonOval;
  2650.     RgnHandle    oldClip, newClip;
  2651.     RGBColor    oldrgb;
  2652.  
  2653.     static RGBColor    whitergb = {0xFFFF, 0xFFFF, 0xFFFF};
  2654.     static RGBColor    grayrgb  = {0x8000, 0x8000, 0x8000};
  2655.     static RGBColor    blackrgb = {0x0000, 0x0000, 0x0000};
  2656.  
  2657.     if (button) {
  2658.         if ((*button)->contrlVis) {
  2659.             GetPort(&oldPort);
  2660.             SetPort((*button)->contrlOwner);
  2661.             GetPenState(&curPen);
  2662.             PenNormal();
  2663.             PenSize(kButtonFrameSize, kButtonFrameSize);
  2664.  
  2665.             theRect = (*button)->contrlRect;
  2666.             InsetRect(&theRect, kButtonFrameInset, kButtonFrameInset);
  2667.             buttonOval = (theRect.bottom - theRect.top) / 2 + 2;
  2668.  
  2669.             GetClip(oldClip = NewRgn());
  2670.             newClip = LocalScreenDepthRegion(4);
  2671.             SectRgn(oldClip, newClip, newClip);
  2672.             SetClip(newClip);
  2673.  
  2674.             if (!EmptyRgn(newClip)) {
  2675.                 GetForeColor(&oldrgb);
  2676.                 switch ((*button)->contrlHilite) {
  2677.                     case kCntlActivate:
  2678.                         RGBForeColor(&blackrgb);
  2679.                         break;
  2680.                     case kCntlDeactivate:
  2681.                         RGBForeColor(&grayrgb);
  2682.                         break;
  2683.                     default:
  2684.                         RGBForeColor(&whitergb);
  2685.                         break;
  2686.                 }
  2687.                 FrameRoundRect(&theRect, buttonOval, buttonOval);
  2688.                 RGBForeColor(&oldrgb);
  2689.             }
  2690.  
  2691.             DiffRgn(oldClip, newClip, newClip);
  2692.             SetClip(newClip);
  2693.             if (!EmptyRgn(newClip)) {
  2694.                 switch ((*button)->contrlHilite) {
  2695.                     case kCntlActivate:
  2696.                         PenPat((ConstPatternParam)&qd.black);
  2697.                         break;
  2698.                     case kCntlDeactivate:
  2699.                         PenPat((ConstPatternParam)&qd.gray);
  2700.                         break;
  2701.                     default:
  2702.                         PenPat((ConstPatternParam)&qd.white);
  2703.                         break;
  2704.                 }
  2705.                 FrameRoundRect(&theRect, buttonOval, buttonOval);
  2706.             }
  2707.  
  2708.             SetClip(oldClip);
  2709.             DisposeRgn(oldClip);
  2710.             DisposeRgn(newClip);
  2711.  
  2712.             SetPenState(&curPen);
  2713.             SetPort(oldPort);
  2714.         }
  2715.     }
  2716. }
  2717.  
  2718.  
  2719.  
  2720. /*****************************************************************************/
  2721.  
  2722.  
  2723.  
  2724. void    OutlineDialogItem(DialogPtr dlgPtr, short item)
  2725. {
  2726.     short    iKind;
  2727.     Handle    iHandle;
  2728.     Rect    iRect;
  2729.  
  2730.     GetDialogItem(dlgPtr, item, &iKind, &iHandle, &iRect);
  2731.     OutlineControl((ControlHandle) iHandle);
  2732. }
  2733.  
  2734.  
  2735.  
  2736. /*****************************************************************************/
  2737.  
  2738.  
  2739.  
  2740. /* Given the button control handle, this will cause the button to look as if it
  2741. ** has been clicked in.  This is nice to do for the user if they type return or
  2742. ** enter to select the default item. */
  2743.  
  2744. void    SelectButton(ControlHandle button)
  2745. {
  2746.     long    finalTicks;
  2747.  
  2748.     UseControlStyle(button);
  2749.     HiliteControl(button, kSelect);
  2750.     Delay(kDelayTime, &finalTicks);
  2751.     HiliteControl(button, kDeselect);
  2752.     UseControlStyle(nil);
  2753. }
  2754.  
  2755.  
  2756.  
  2757. /*****************************************************************************/
  2758.  
  2759.  
  2760.  
  2761. /* Handy function for setting the value of a radio button.  Given a dialog
  2762. ** pointer, and item number, and a state, this function will take care of the
  2763. ** rest. */
  2764.  
  2765. void    SetCheckOrRadioButton(DialogPtr dlgPtr, short itemNo, short state)
  2766. {
  2767.     short    iKind;
  2768.     Handle    iHandle;
  2769.     Rect    iRect;
  2770.  
  2771.     GetDialogItem(dlgPtr, itemNo, &iKind, &iHandle, &iRect);
  2772.     SetControlValue((ControlHandle)iHandle, state);
  2773. }
  2774.  
  2775.  
  2776.  
  2777. /*****************************************************************************/
  2778.  
  2779.  
  2780.  
  2781. void    ToggleCheck(DialogPtr dlgPtr, short chkItem)
  2782. {
  2783.     short    iKind;
  2784.     Handle    iHandle;
  2785.     Rect    iRect;
  2786.  
  2787.     GetDialogItem(dlgPtr, chkItem, &iKind, &iHandle, &iRect);
  2788.     SetControlValue((ControlHandle) iHandle, !GetControlValue((ControlHandle)iHandle));
  2789. }
  2790.  
  2791.  
  2792.  
  2793. /*****************************************************************************/
  2794.  
  2795.  
  2796.  
  2797. Boolean    WhichControl(Point mouseLoc, long when, WindowPtr window, ControlHandle *ctlHit)
  2798. {
  2799.     Boolean                    found;
  2800.     Rect                    rct;
  2801.     ControlHandle            ctl, lastCtl;
  2802.     static ControlHandle    lastWhenCtl;
  2803.  
  2804.     gWhichCtlTracking = false;
  2805.  
  2806.     found   = false;
  2807.     lastCtl = nil;
  2808.  
  2809.     if (ctlHit)
  2810.         *ctlHit = nil;
  2811.  
  2812.     if (window) {
  2813.         ctl = ((WindowPeek)window)->controlList;
  2814.         while (ctl) {
  2815.             if ((*ctl)->contrlVis) {
  2816.                 rct = (*ctl)->contrlRect;
  2817.                 if (PtInRect(mouseLoc, &rct)) {
  2818.                     found = true;            /* Return the last hit in the linked list, as */
  2819.                     lastCtl = ctl;            /* it is drawn last, and therefore on top.    */
  2820.                 }
  2821.             }
  2822.             ctl = (*ctl)->nextControl;
  2823.         }
  2824.     }
  2825.  
  2826.     if (ctlHit)
  2827.         *ctlHit = lastCtl;
  2828.  
  2829.     gWhichCtlDbl = false;
  2830.     if (when) {
  2831.         gWhichCtlHit = lastWhenCtl;
  2832.         lastWhenCtl  = lastCtl;
  2833.         if (gWhichCtlHit == lastCtl)
  2834.             if (when < gWhichCtlWhen + 30)
  2835.                 gWhichCtlDbl = true;
  2836.         gWhichCtlWhen = when;
  2837.     }
  2838.     gWhichCtlHit = lastCtl;
  2839.  
  2840.     return(found);
  2841. }
  2842.  
  2843.  
  2844.  
  2845. /*****************************************************************************/
  2846.  
  2847.  
  2848.  
  2849. void    DoDrawControls(WindowPtr window, Boolean scrollBarsOnly)
  2850. {
  2851.     ControlHandle    ctl;
  2852.  
  2853.     ctl = ((WindowPeek)window)->controlList;
  2854.     while (ctl) {
  2855.         DoDraw1Control(ctl, scrollBarsOnly);
  2856.         ctl = (*ctl)->nextControl;
  2857.     }
  2858. }
  2859.  
  2860.  
  2861.  
  2862. /*****************************************************************************/
  2863.  
  2864.  
  2865.  
  2866. void    DoDraw1Control(ControlHandle ctl, Boolean scrollBarsOnly)
  2867. {
  2868.     WindowPtr    window, oldPort;
  2869.     Rect        rct, srct;
  2870.     Point        org;
  2871.     RgnHandle    oldClip, newClip;
  2872.     Boolean        didPopup;
  2873.  
  2874.     window = (*ctl)->contrlOwner;
  2875.     rct  = (*(window->visRgn))->rgnBBox;
  2876.     srct = (*(window->clipRgn))->rgnBBox;
  2877.     SectRect(&rct, &srct, &srct);
  2878.  
  2879.     rct = (*ctl)->contrlRect;
  2880.     InsetRect(&rct, -4, -4);    /* Enclose possible control adornments. */
  2881.     SectRect(&rct, &srct, &srct);
  2882.     if (EmptyRect(&srct))
  2883.         if (!(window->picSave))
  2884.             return;
  2885.  
  2886.     if (IsScrollBar(ctl)) {
  2887.         if (((WindowPeek)window)->hilited)
  2888.             Draw1Control(ctl);
  2889.         else {
  2890.             if ((*ctl)->contrlVis) {
  2891.                 GetPort(&oldPort);
  2892.                 SetPort(window);
  2893.                 rct = (*ctl)->contrlRect;
  2894.                 FrameRect(&rct);
  2895.                 InsetRect(&rct, 1, 1);
  2896.                 EraseRect(&rct);
  2897.                 SetPort(oldPort);
  2898.             }
  2899.         }
  2900.     }
  2901.     else {
  2902.         if (!scrollBarsOnly) {
  2903.             UseControlStyle(ctl);
  2904.             didPopup = false;
  2905.             if (gPopupProc) {        /* The popup control does not handle negative coords. */
  2906.                 if (StripAddress((*ctl)->contrlDefProc) == StripAddress(gPopupProc)) {
  2907.                     didPopup = true;
  2908.                     GetPort(&oldPort);
  2909.                     SetPort(window);
  2910.                     GetClip(oldClip = NewRgn());    /* We draw it once, so that internals   */
  2911.                     SetRect(&srct, 0, 0, 0, 0);        /* are fixed up.  We don't want to show */
  2912.                     ClipRect(&srct);                /* a flash though. */
  2913.  
  2914.                     RectRgn(newClip = NewRgn(), &(window->portRect));
  2915.                     org.h = window->portRect.left;
  2916.                     org.v = window->portRect.top;
  2917.                     SetOrigin(0, 0);
  2918.  
  2919.                     OffsetRect(&((*ctl)->contrlRect), -org.h, -org.v);    /* Completely clipped out. */
  2920.                     Draw1Control(ctl);                                    /* Just to fix internals.  */
  2921.  
  2922.                     SectRgn(newClip, oldClip, newClip);
  2923.                     OffsetRgn(newClip, -org.h, -org.v);
  2924.                     SetClip(newClip);
  2925.                     Draw1Control(ctl);                /* Now really draw it. */
  2926.  
  2927.                     OffsetRect(&((*ctl)->contrlRect), org.h, org.v);
  2928.                     SetOrigin(org.h, org.v);
  2929.                     SetClip(oldClip);
  2930.                     DisposeRgn(newClip);
  2931.                     DisposeRgn(oldClip);
  2932.  
  2933.                     SetPort(oldPort);
  2934.                 }
  2935.             }
  2936.             if (!didPopup) {
  2937.                 if ((*ctl)->contrlVis) {
  2938.                     if (gDrawControl)
  2939.                         (*gDrawControl)(ctl);
  2940.                     else
  2941.                         Draw1Control(ctl);
  2942.                 }
  2943.             }
  2944.             UseControlStyle(nil);
  2945.             if (GetControlValue(ctl) == 1) {
  2946.                 if (GetButtonVariant(ctl) == pushButProc)
  2947.                     OutlineControl(ctl);
  2948.             }
  2949.         }
  2950.     }
  2951. }
  2952.  
  2953.  
  2954.  
  2955. /*****************************************************************************/
  2956.  
  2957.  
  2958.  
  2959. /* GetPopupCtlHandle takes a dialog and its item number and (assuming it is a
  2960. ** popup menu control) and returns the control handle for the popup. */
  2961.  
  2962. ControlHandle    GetPopupCtlHandle(DialogPtr theDialog, short itemNum)
  2963. {
  2964.     short        theType;
  2965.     Handle        theHndl;
  2966.     Rect        theBox;
  2967.  
  2968.     GetDialogItem(theDialog, itemNum, &theType, &theHndl, &theBox);
  2969.     return((ControlHandle)theHndl);
  2970. }
  2971.  
  2972.  
  2973.  
  2974. /*****************************************************************************/
  2975.  
  2976.  
  2977.  
  2978. /* GetPopupMenuHandle takes a popup control and returns the menu handle from
  2979. ** the control. */
  2980.  
  2981. MenuHandle    GetPopupMenuHandle(ControlHandle popupCtl)
  2982. {
  2983.     PopupCtlDataHandle    popupData;
  2984.  
  2985.     popupData = (PopupCtlDataHandle)(*popupCtl)->contrlData;
  2986.     if (popupData)
  2987.         return((*popupData)->mHandle);
  2988.  
  2989.     return(nil);
  2990. }
  2991.  
  2992.  
  2993.  
  2994. /*****************************************************************************/
  2995.  
  2996.  
  2997.  
  2998. /* GetPopupCtlValue returns value for the popup control. */
  2999.  
  3000. short    GetPopupCtlValue(DialogPtr theDialog, short popItem)
  3001. {
  3002.     ControlHandle    popupCtl;
  3003.  
  3004.     popupCtl = GetPopupCtlHandle(theDialog, popItem);
  3005.     if (popupCtl)
  3006.         return(GetControlValue(popupCtl));
  3007.  
  3008.     return(-1);
  3009. }
  3010.  
  3011.  
  3012.  
  3013. /*****************************************************************************/
  3014.  
  3015.  
  3016.  
  3017. /* SetPopupCtlValue makes value the new value for the popup control. */
  3018.  
  3019. void    SetPopupCtlValue(DialogPtr theDialog, short popItem, short value)
  3020. {
  3021.     ControlHandle    popupCtl;
  3022.  
  3023.     popupCtl = GetPopupCtlHandle(theDialog, popItem);
  3024.     if (popupCtl) {
  3025.         (*popupCtl)->contrlValue = value;
  3026.         DoDraw1Control(popupCtl, false);
  3027.     }
  3028. }
  3029.  
  3030.  
  3031.  
  3032. /*****************************************************************************/
  3033. /*****************************************************************************/
  3034. /*****************************************************************************/
  3035.  
  3036.  
  3037.  
  3038. OSErr    SetControlStyle(ControlHandle ctl, ControlStyleInfoPtr cinfo)
  3039. {
  3040.     short                len, tlen, ofst;
  3041.     OSErr                err;
  3042.     ControlStyleInfo    cin;
  3043.     Ptr                    ptr1, ptr2;
  3044.  
  3045.     tlen = (*ctl)->contrlTitle[0];
  3046.     ofst = offsetof(ControlRecord,contrlTitle) + tlen + 1;
  3047.     if (!cinfo) {
  3048.         SetHandleSize((Handle)ctl, ofst);
  3049.         return(noErr);
  3050.     }        /* If no info, then control is normalized. */
  3051.  
  3052.     cin   = *cinfo;
  3053.     ptr1  = (Ptr)&cin + offsetof(ControlStyleInfo,font);            /* Point at font. */
  3054.     ptr1 += ptr1[0] + 1;                                            /* Point at packed keyEquivs. */
  3055.     ptr2  = (Ptr)&cin + offsetof(ControlStyleInfo,keyEquivs);        /* Point at keyEquivs. */
  3056.     BlockMove(ptr2, ptr1, ptr2[0] + 1);
  3057.     ptr1 += ptr1[0] + 1;                                            /* Point at packed balloonHelp. */
  3058.     ptr2  = (Ptr)&cin + offsetof(ControlStyleInfo,balloonHelp);        /* Point at balloonHelp. */
  3059.     BlockMove(ptr2, ptr1, ptr2[0] + 1);
  3060.     ptr1 += ptr1[0] + 1;                                            /* Point past packed balloonHelp. */
  3061.  
  3062.     len = ptr1 - (Ptr)&cin;
  3063.     SetHandleSize((Handle)ctl, ofst + len);
  3064.     err = MemError();
  3065.     if (err) {
  3066.         SetHandleSize((Handle)ctl, ofst);
  3067.         return(err);
  3068.     }
  3069.  
  3070.     BlockMove((Ptr)&cin, ((Ptr)*ctl) + ofst, len);
  3071.     return(noErr);
  3072. }
  3073.  
  3074.  
  3075.  
  3076. /*****************************************************************************/
  3077.  
  3078.  
  3079.  
  3080. Boolean    GetControlStyle(ControlHandle ctl, ControlStyleInfoPtr cinfo)
  3081. {
  3082.     short    clen, tlen, ofst, ofst2, ofst3;
  3083.     Ptr        ptr;
  3084.  
  3085.     clen = GetHandleSize((Handle)ctl);
  3086.     tlen = (*ctl)->contrlTitle[0];
  3087.     ofst = offsetof(ControlRecord,contrlTitle) + tlen + 1;
  3088.     if (clen < ofst + sizeof(short)) return(false);
  3089.  
  3090.     if (cinfo) {
  3091.         ptr = (Ptr)*ctl;
  3092.         BlockMove(ptr + ofst, (Ptr)cinfo, clen - ofst);
  3093.         ptr   = (Ptr)cinfo;
  3094.         ofst  = offsetof(ControlStyleInfo,font);        /* font */
  3095.         ofst2 = ofst  + ptr[ofst]  + 1;                    /* keyEquivs */
  3096.         ofst3 = ofst2 + ptr[ofst2] + 1;                    /* balloonHelp */
  3097.         BlockMove(ptr + ofst3, ptr + offsetof(ControlStyleInfo,balloonHelp), ptr[ofst3] + 1);
  3098.         BlockMove(ptr + ofst2, ptr + offsetof(ControlStyleInfo,keyEquivs),   ptr[ofst2] + 1);
  3099.     }
  3100.  
  3101.     return(true);
  3102. }
  3103.  
  3104.  
  3105.  
  3106. /*****************************************************************************/
  3107.  
  3108.  
  3109.  
  3110. void    SetTrackControlProc(ControlHandle ctl, TrackControlProcPtr proc)
  3111. {
  3112.     ControlStyleInfo    cinfo;
  3113.  
  3114.     if (GetControlStyle(ctl, &cinfo)) {
  3115.         cinfo.trackProc = proc;
  3116.         SetControlStyle(ctl, &cinfo);
  3117.     }
  3118. }
  3119.  
  3120.  
  3121.  
  3122. /*****************************************************************************/
  3123.  
  3124.  
  3125.  
  3126. short    GetControlID(ControlHandle ctl)
  3127. {
  3128.     short    tlen, ofst, id;
  3129.  
  3130.     tlen = (*ctl)->contrlTitle[0];
  3131.     ofst = offsetof(ControlRecord,contrlTitle) + tlen + 1;
  3132.     if (GetHandleSize((Handle)ctl) < ofst + sizeof(short)) return(0);
  3133.  
  3134.     BlockMove(((Ptr)*ctl) + ofst, &id, sizeof(short));
  3135.     return(id);
  3136. }
  3137.  
  3138.  
  3139.  
  3140. /*****************************************************************************/
  3141.  
  3142.  
  3143.  
  3144. void    SetStyledCTitle(ControlHandle ctl, StringPtr title)
  3145. {
  3146.     ControlStyleInfo    cinfo;
  3147.     Boolean                hasStyle;
  3148.     char                vv;
  3149.  
  3150.     vv = (*ctl)->contrlVis;
  3151.     (*ctl)->contrlVis = 0;
  3152.  
  3153.     hasStyle = GetControlStyle(ctl, &cinfo);
  3154.     SetControlTitle(ctl, title);
  3155.     if (hasStyle)
  3156.         SetControlStyle(ctl, &cinfo);
  3157.  
  3158.     (*ctl)->contrlVis = vv;
  3159.     DoDraw1Control(ctl, false);
  3160. }
  3161.  
  3162.  
  3163.  
  3164. /*****************************************************************************/
  3165.  
  3166.  
  3167.  
  3168. void    UseControlStyle(ControlHandle ctl)
  3169. {
  3170.     WindowPtr            oldPort;
  3171.     short                fnum;
  3172.     ControlStyleInfo    cinfo;
  3173.     static short        txFont, txSize;
  3174.     static Style        txFace;
  3175.     static WindowPtr    ctlWindow;
  3176.  
  3177.     if (!ctl) {
  3178.         gDrawControl = nil;
  3179.         if (ctlWindow) {
  3180.             GetPort(&oldPort);
  3181.             SetPort(ctlWindow);
  3182.             TextFont(txFont);
  3183.             TextSize(txSize);
  3184.             TextFace(txFace);
  3185.             SetPort(oldPort);
  3186.         }
  3187.         return;
  3188.     }
  3189.  
  3190.     ctlWindow = nil;
  3191.     if (GetControlStyle(ctl, &cinfo)) {
  3192.         gDrawControl = cinfo.drawControl;
  3193.         if (GetControlVariant(ctl) & useWFont) {
  3194.             GetPort(&oldPort);
  3195.             SetPort(ctlWindow = (*ctl)->contrlOwner);
  3196.             txFont = ctlWindow->txFont;
  3197.             txSize = ctlWindow->txSize;
  3198.             txFace = ctlWindow->txFace;
  3199.             TextFace(cinfo.fontStyle);
  3200.             fnum = systemFont;
  3201.             if (cinfo.font[0])
  3202.                 GetFNum(cinfo.font, &fnum);
  3203.             TextFont(fnum);
  3204.             TextSize(cinfo.fontSize);
  3205.             SetPort(oldPort);
  3206.         }
  3207.     }
  3208. }
  3209.  
  3210.  
  3211.  
  3212. /*****************************************************************************/
  3213. /*****************************************************************************/
  3214. /*****************************************************************************/
  3215.  
  3216.  
  3217.  
  3218. Boolean    ControlKeyEquiv(WindowPtr window, EventRecord *event, ControlHandle *retCtl, StringPtr defaultEquivs)
  3219. {
  3220.     ControlHandle        ctl;
  3221.     ControlStyleInfo    cinfo;
  3222.     short                i, theChr, cc, theMod, equivChr, modMask, modVal, pass;
  3223.     Boolean                keyok;
  3224.  
  3225.     if (retCtl)
  3226.         *retCtl = nil;
  3227.  
  3228.     if ((event->what != keyDown) && (event->what != autoKey)) return(false);
  3229.  
  3230.     keyok  = (event->what != autoKey) ? true : false;
  3231.     theChr = event->message   & charCodeMask;
  3232.     theMod = event->modifiers & keyCodeMask;
  3233.  
  3234.     for (pass = 0; pass < 2; ++pass) {
  3235.         for (ctl = ((WindowPeek)window)->controlList; ctl; ctl = (*ctl)->nextControl) {
  3236.             if (!(*ctl)->contrlVis)   continue;        /* Control not visible, so next control. */
  3237.             if ((*ctl)->contrlHilite) continue;        /* Control not active, so next control. */
  3238.             cinfo.keyEquivs[0] = 0;
  3239.             switch (pass) {
  3240.                 case 0:
  3241.                     GetControlStyle(ctl, &cinfo);
  3242.                     break;
  3243.                 case 1:
  3244.                     if (GetButtonVariant(ctl) == pushButProc)                /* If simple button... */
  3245.                         if (GetControlValue(ctl) == 1)                        /* If is outlined button... */
  3246.                             if (defaultEquivs)                                /* If default equiv text passed in... */
  3247.                                 pcpy(cinfo.keyEquivs, defaultEquivs)    ;    /* Use it. */
  3248.                     break;
  3249.             }
  3250.             for (i = 1; i < cinfo.keyEquivs[0]; i += 7) {
  3251.                 if (cinfo.keyEquivs[i] == (unsigned char)':') break;
  3252.                 cc = theChr;
  3253.                 if (cinfo.keyEquivs[i] == (unsigned char)'≈')
  3254.                     if ((cc >= 'a') && (cc <= 'z')) cc -= 32;
  3255.                 equivChr = GetHexByte((char *)(cinfo.keyEquivs + i));
  3256.                 modMask  = GetHexByte((char *)(cinfo.keyEquivs + i + 2)) << 8;
  3257.                 modVal   = GetHexByte((char *)(cinfo.keyEquivs + i + 4)) << 8;
  3258.                 if (!keyok) {
  3259.                     if (equivChr == 0x0000)
  3260.                         if (modMask == 0x0000)
  3261.                             if (modVal == 0x0100)
  3262.                                 keyok = true;
  3263.                     continue;
  3264.                 }
  3265.                 if (cc == equivChr) {
  3266.                     if ((theMod & modMask) == modVal) {
  3267.                         if (retCtl)
  3268.                             *retCtl = ctl;
  3269.                         return(true);
  3270.                     }
  3271.                 }
  3272.             }
  3273.         }
  3274.     }
  3275.  
  3276.     return(false);
  3277. }
  3278.  
  3279.  
  3280.  
  3281.